def create_encryption_event(encr_result, key_fingerprint): """Return a PREMIS:EVENT for the encryption event.""" # First line of stdout from ``gpg --version`` is expected to be # something like 'gpg (GnuPG) 1.4.16' gpg_version = subprocess.check_output(['gpg', '--version' ]).splitlines()[0].split()[-1] # detail = escape( # 'program=gpg (GnuPG); version={}; python-gnupg; version={}'.format( # gpg_version, gnupg.__version__)) detail = escape('program=GPG; version={}; key={}'.format( gpg_version, key_fingerprint)) outcome_detail_note = 'Status="{}"; Standard Error="{}"'.format( encr_result.status.replace('"', r'\"'), encr_result.stderr.replace('"', r'\"').strip()) agents = utils.get_ss_premis_agents() event = [ 'event', premisrw.PREMIS_META, ( 'event_identifier', ('event_identifier_type', 'UUID'), ('event_identifier_value', str(uuid4())), ), ('event_type', 'encryption'), ('event_date_time', utils.mets_file_now()), ('event_detail', detail), ('event_outcome_information', ('event_outcome', 'success'), ('event_outcome_detail', ('event_outcome_detail_note', outcome_detail_note))) ] event = tuple(utils.add_agents_to_event_as_list(event, agents)) return premisrw.PREMISEvent(data=event)
def create_encryption_event(encr_result, key_fingerprint): """Return a PREMIS:EVENT for the encryption event.""" gpg_version = _get_gpg_version() detail = escape( 'program=GPG; version={}; key={}'.format( gpg_version, key_fingerprint)) outcome_detail_note = 'Status="{}"; Standard Error="{}"'.format( encr_result.status.replace('"', r'\"'), encr_result.stderr.replace('"', r'\"').strip()) agents = utils.get_ss_premis_agents() event = [ 'event', premisrw.PREMIS_META, ( 'event_identifier', ('event_identifier_type', 'UUID'), ('event_identifier_value', str(uuid4())), ), ('event_type', 'encryption'), ('event_date_time', utils.mets_file_now()), ('event_detail', detail), ( 'event_outcome_information', ('event_outcome', 'success'), ( 'event_outcome_detail', ('event_outcome_detail_note', outcome_detail_note) ) ) ] event = tuple(utils.add_agents_to_event_as_list(event, agents)) return premisrw.PREMISEvent(data=event)
def create_test_pointer_file(self): # 1. Get the PREMIS events and object as premisrw class instances. compression_event = premisrw.PREMISEvent(data=c.EX_COMPR_EVT) events = [compression_event] _, compression_program_version, archive_tool = ( compression_event.compression_details) premis_object = premisrw.PREMISObject( xsi_type=c.EX_PTR_XSI_TYPE, identifier_value=c.EX_PTR_IDENTIFIER_VALUE, message_digest_algorithm=c.EX_PTR_MESSAGE_DIGEST_ALGORITHM, message_digest=c.EX_PTR_MESSAGE_DIGEST, size=c.EX_PTR_SIZE, format_name=c.EX_PTR_FORMAT_NAME, format_registry_key=c.EX_PTR_FORMAT_REGISTRY_KEY, creating_application_name=archive_tool, creating_application_version=compression_program_version, date_created_by_application=c.EX_PTR_DATE_CREATED_BY_APPLICATION) transform_files = compression_event.get_decompression_transform_files() # 2. Construct the METS pointer file mw = metsrw.METSDocument() mets_fs_entry = metsrw.FSEntry(path=c.EX_PTR_PATH, file_uuid=c.EX_PTR_IDENTIFIER_VALUE, use=c.EX_PTR_PACKAGE_TYPE, type=c.EX_PTR_PACKAGE_TYPE, transform_files=transform_files, mets_div_type=c.EX_PTR_AIP_SUBTYPE) mets_fs_entry.add_premis_object(premis_object.serialize()) for event in events: mets_fs_entry.add_premis_event(event.serialize()) for agent in [c.EX_AGT_1, c.EX_AGT_2]: mets_fs_entry.add_premis_agent(premisrw.data_to_premis(agent)) mw.append_file(mets_fs_entry) return mw
def test_premis_event_cls_data(self): """Tests that you can pass a Python tuple as the ``data`` argument to ``PREMISEvent`` to construct an instance. """ premis_obj = premisrw.PREMISEvent(data=c.EX_COMPR_EVT) lxml_el = premis_obj.serialize() data = premisrw.premis_to_data(lxml_el) assert data == c.EX_COMPR_EVT
def test_premis_event_cls_kwargs(self): """You should be able to pass sanely-named kwargs to ``PREMISEvent`` on instantiation. """ premis_obj = premisrw.PREMISEvent( identifier_value=c.EX_COMPR_EVT_IDENTIFIER_VALUE, type=c.EX_COMPR_EVT_TYPE, date_time=c.EX_COMPR_EVT_DATE_TIME, detail=c.EX_COMPR_EVT_DETAIL, outcome_detail_note=c.EX_COMPR_EVT_OUTCOME_DETAIL_NOTE, linking_agent_identifier=c.EX_COMPR_EVT_AGENTS) lxml_el = premis_obj.serialize() data = premisrw.premis_to_data(lxml_el) assert data == c.EX_COMPR_EVT
def test_dependency_injection(self): """Test the dependency injection (DI) infrastructure for metsrw plugins. - client: metsrw.FSEntry - services: classes for reading and writing metadata elements, e.g., the PREMISObject class of metsrw.plugins.premisrw or other classes exposing the same interface. - injector: this test code or the code in metsrw/di.py which calls ``provide`` on the ``feature_broker`` singleton. The ``FSEntry`` class declares its dependency on the class attributes ``premis_object_class``, ``premis_event_class``, and ``premis_agent_class`` and further requires that these return classes with ``fromtree`` and ``serialize`` methods:: >>> premis_object_class = Dependency( ... has_methods('serialize'), ... has_class_methods('fromtree'), ... is_class) """ # 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 feature_broker.clear() assert not feature_broker feature_broker.provide('premis_object_class', premisrw.PREMISObject) feature_broker.provide('premis_event_class', premisrw.PREMISEvent) feature_broker.provide('premis_agent_class', premisrw.PREMISAgent) assert len(feature_broker) == 3 # Create premisrw instances. compression_premis_event = premisrw.PREMISEvent(data=EX_COMPR_EVT) premis_events = [compression_premis_event] premis_agents = [ premisrw.PREMISAgent(data=x) for x in [EX_AGT_1, EX_AGT_2] ] _, compression_program_version, archive_tool = ( compression_premis_event.compression_details) premis_object = premisrw.PREMISObject( xsi_type=EX_PTR_XSI_TYPE, identifier_value=EX_PTR_IDENTIFIER_VALUE, message_digest_algorithm=EX_PTR_MESSAGE_DIGEST_ALGORITHM, message_digest=EX_PTR_MESSAGE_DIGEST, size=EX_PTR_SIZE, format_name=EX_PTR_FORMAT_NAME, format_registry_key=EX_PTR_FORMAT_REGISTRY_KEY, creating_application_name=archive_tool, creating_application_version=compression_program_version, date_created_by_application=EX_PTR_DATE_CREATED_BY_APPLICATION) transform_files = compression_premis_event.get_decompression_transform_files( ) # 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) for premis_event in premis_events: fs_entry.add_premis_event(premis_event) for premis_agent in premis_agents: fs_entry.add_premis_agent(premis_agent) # Assert that the instances returned by the # ``FSEntry().get_premis_...`` methods are of the anticipated type. new_premis_agents = fs_entry.get_premis_agents() for new_premis_agent in new_premis_agents: assert isinstance(new_premis_agent, premisrw.PREMISAgent) assert new_premis_agent in premis_agents assert id(new_premis_agent) not in [id(pa) for pa in premis_agents] new_premis_events = fs_entry.get_premis_events() for new_premis_event in new_premis_events: assert isinstance(new_premis_event, premisrw.PREMISEvent) assert new_premis_event in premis_events assert id(new_premis_event) not in [id(pa) for pa in premis_events] new_premis_objects = fs_entry.get_premis_objects() for new_premis_object in new_premis_objects: assert isinstance(new_premis_object, premisrw.PREMISObject) assert new_premis_object == premis_object assert id(new_premis_object) is not premis_object # Assert that the resulting mets XML contains a # premis:objectIdentifierValue in the anticipated location in the # structure with the anticipated value. mets_doc_el = mets_doc.serialize() xpath = ('mets:amdSec/mets:techMD/mets:mdWrap[@MDTYPE="PREMIS:OBJECT"]' '/mets:xmlData/premis:object/premis:objectIdentifier/' 'premis:objectIdentifierValue') a = mets_doc_el.find(xpath, namespaces=metsrw.NAMESPACES) assert a.text == EX_PTR_IDENTIFIER_VALUE # Now change the feature broker so that ``FSEntry``'s dependency on a # ``premis_object_class`` class attribute is being fulfilled by a new # class: ``BetterPREMISObject``. feature_broker.provide('premis_object_class', BetterPREMISObject) # Now create a new PREMIS object premis_object_tree = premis_object.serialize() better_premis_object = BetterPREMISObject.fromtree(premis_object_tree) # And re-create the ``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) # Add the PREMIS metadata again, but this time use the instance of # ``BetterPREMISObject``. fs_entry.add_premis_object(better_premis_object) for premis_event in premis_events: fs_entry.add_premis_event(premis_event) for premis_agent in premis_agents: fs_entry.add_premis_agent(premis_agent) # Assert that the instances returned by the # ``FSEntry().get_premis_...`` methods are of the anticipated type. new_premis_objects = fs_entry.get_premis_objects() for new_premis_object in new_premis_objects: assert isinstance(new_premis_object, BetterPREMISObject) # Make sure we can still find the PREMIS object id value. mets_doc_el = mets_doc.serialize() assert (mets_doc_el.find( xpath, namespaces=metsrw.NAMESPACES).text == 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)
def test_attr_get_set(self): compression_event = premisrw.PREMISEvent(data=c.EX_COMPR_EVT) _, compression_program_version, archive_tool = ( compression_event.compression_details) INHIBITORS = (('inhibitors', ('inhibitor_type', 'GPG'), ('inhibitor_target', 'All content')), ('inhibitors', ('inhibitor_type', 'Password protection'), ('inhibitor_target', 'Function: Play'))) old_premis_object = premisrw.PREMISObject( xsi_type=c.EX_PTR_XSI_TYPE, identifier_value=c.EX_PTR_IDENTIFIER_VALUE, message_digest_algorithm=c.EX_PTR_MESSAGE_DIGEST_ALGORITHM, message_digest=c.EX_PTR_MESSAGE_DIGEST, size=c.EX_PTR_SIZE, format_name=c.EX_PTR_FORMAT_NAME, format_registry_key=c.EX_PTR_FORMAT_REGISTRY_KEY, creating_application_name=archive_tool, creating_application_version=compression_program_version, date_created_by_application=c.EX_PTR_DATE_CREATED_BY_APPLICATION, relationship=c.EX_RELATIONSHIP_1) assert old_premis_object.relationship == (c.EX_RELATIONSHIP_1, ) new_composition_level = str( int(old_premis_object.composition_level) + 1) new_premis_object = premisrw.PREMISObject( xsi_type=old_premis_object.xsi_type, identifier_value=old_premis_object.identifier_value, message_digest_algorithm=old_premis_object. message_digest_algorithm, message_digest=old_premis_object.message_digest, size=old_premis_object.size, format_name=old_premis_object.format_name, format_registry_key=old_premis_object.format_registry_key, creating_application_name=old_premis_object. creating_application_name, creating_application_version=old_premis_object. creating_application_version, date_created_by_application=old_premis_object. date_created_by_application, # New attributes: relationship=[ old_premis_object.relationship[0].data, c.EX_RELATIONSHIP_2 ], inhibitors=INHIBITORS, composition_level=new_composition_level) for attr in ('xsi_type', 'identifier_value', 'message_digest_algorithm', 'message_digest', 'size', 'format_name', 'format_registry_key', 'creating_application_name', 'creating_application_version', 'date_created_by_application'): assert getattr(old_premis_object, attr) == getattr(new_premis_object, attr) assert not old_premis_object.inhibitors assert new_premis_object.inhibitors == INHIBITORS assert old_premis_object.composition_level == '1' assert new_premis_object.composition_level == new_composition_level assert (old_premis_object.relationship[0], c.EX_RELATIONSHIP_2) == (new_premis_object.relationship) # Here are two ways to create a new PREMIS:OBJECT that's just like an # old one. # 1. Just pass in its data via the data kw new_premis_object = premisrw.PREMISObject(data=old_premis_object.data) assert new_premis_object == old_premis_object # 2. ... new_premis_object = premisrw.PREMISObject( xsi_type=old_premis_object.xsi_type, object_identifier=old_premis_object.find('object_identifier'), object_characteristics=old_premis_object.find( 'object_characteristics'), relationship=old_premis_object.find('relationship')) assert new_premis_object == old_premis_object new_relationships = [ r.data for r in old_premis_object.findall('relationship') ] new_relationships.append(c.EX_RELATIONSHIP_2) new_premis_object = premisrw.PREMISObject( xsi_type=old_premis_object.xsi_type, object_identifier=old_premis_object.find('object_identifier'), object_characteristics=old_premis_object.find( 'object_characteristics'), relationship=new_relationships) assert new_premis_object.object_identifier == old_premis_object.object_identifier assert new_premis_object.object_characteristics == old_premis_object.object_characteristics assert new_premis_object.relationship != old_premis_object.relationship assert old_premis_object.find( 'relationship') in new_premis_object.findall('relationship')
def test_encryption_event(self): encryption_event = premisrw.PREMISEvent(data=c.EX_ENCR_EVT) decr_tf = encryption_event.get_decryption_transform_file() assert decr_tf['algorithm'] == 'GPG' assert decr_tf['order'] == '1' assert decr_tf['type'] == 'decryption'
def test_dynamic_attrs(self): """Tests that dynamic attribute accession works correctly on PREMISElement subclasses. This allows us to use the output of the ``generate_data`` abstract method to dynamically create accessors for PREMIS entities, e.g., ``PREMISObject().identifier_value`` and ``PREMISObject().object_identifier_value`` should both return the value of the element at 'object_identifier/object_identifier_value' even though ``PREMISObject`` does not explicitly define either of those attributes. """ compression_event = premisrw.PREMISEvent(data=c.EX_COMPR_EVT) _, compression_program_version, archive_tool = ( compression_event.compression_details) inhibitors1 = ('inhibitors', ('inhibitorType', 'GPG'), ('inhibitorTarget', 'All content')) premis_object = premisrw.PREMISObject( xsi_type=c.EX_PTR_XSI_TYPE, identifier_value=c.EX_PTR_IDENTIFIER_VALUE, message_digest_algorithm=c.EX_PTR_MESSAGE_DIGEST_ALGORITHM, message_digest=c.EX_PTR_MESSAGE_DIGEST, size=c.EX_PTR_SIZE, format_name=c.EX_PTR_FORMAT_NAME, format_registry_key=c.EX_PTR_FORMAT_REGISTRY_KEY, creating_application_name=archive_tool, creating_application_version=compression_program_version, date_created_by_application=c.EX_PTR_DATE_CREATED_BY_APPLICATION, inhibitors=[inhibitors1]) assert premis_object.format_name == c.EX_PTR_FORMAT_NAME assert premis_object.identifier_value == c.EX_PTR_IDENTIFIER_VALUE assert premis_object.object_identifier_value == c.EX_PTR_IDENTIFIER_VALUE assert premis_object.message_digest == c.EX_PTR_MESSAGE_DIGEST assert premis_object.object_characteristics__fixity__message_digest == c.EX_PTR_MESSAGE_DIGEST # A partial path to a leaf element is not a valid accessor: with pytest.raises(AttributeError): premis_object.fixity__message_digest # XML attribute accessors assert premis_object.xsi_type == c.EX_PTR_XSI_TYPE # namespaced assert premis_object.xsi__type == c.EX_PTR_XSI_TYPE # namespaced assert premis_object.type == c.EX_PTR_XSI_TYPE # not namespaced assert premis_object.xsi_schema_location == ( premisrw.PREMIS_META['xsi:schema_location']) assert compression_event.event_type == c.EX_COMPR_EVT_TYPE assert compression_event.type == c.EX_COMPR_EVT_TYPE assert compression_event.event_detail == c.EX_COMPR_EVT_DETAIL assert compression_event.detail == c.EX_COMPR_EVT_DETAIL premis_agent_1 = premisrw.PREMISAgent(data=c.EX_AGT_1) assert premis_agent_1.name == c.EX_AGT_1_NAME assert premis_agent_1.type == c.EX_AGT_1_TYPE assert premis_agent_1.identifier_type == c.EX_AGT_1_IDENTIFIER_TYPE assert premis_agent_1.identifier_value == c.EX_AGT_1_IDENTIFIER_VALUE assert premis_agent_1.agent_name == c.EX_AGT_1_NAME assert premis_agent_1.agent_type == c.EX_AGT_1_TYPE assert premis_agent_1.agent_identifier_type == c.EX_AGT_1_IDENTIFIER_TYPE assert premis_agent_1.agent_identifier_value == c.EX_AGT_1_IDENTIFIER_VALUE assert premis_agent_1.agent_identifier__agent_identifier_type == c.EX_AGT_1_IDENTIFIER_TYPE with pytest.raises(AttributeError): premis_agent_1.agent_identifier__agent_name