diff --git a/src/calibre/ebooks/metadata/opf3.py b/src/calibre/ebooks/metadata/opf3.py index 7d3baf45ec..fa805a8de4 100644 --- a/src/calibre/ebooks/metadata/opf3.py +++ b/src/calibre/ebooks/metadata/opf3.py @@ -256,25 +256,29 @@ def set_identifiers(root, prefixes, refines, new_identifiers, force_identifiers= p = package_identifier.getparent() p.insert(p.index(package_identifier), ident) -def set_application_id(root, refines, new_application_id=None): - uid = root.get('unique-identifier') - package_identifier = None - for ident in XPath('./opf:metadata/dc:identifier')(root): - is_package_id = uid is not None and uid == ident.get('id') - if is_package_id: - package_identifier = ident - val = (ident.text or '').strip() - if val.startswith('calibre:') and not is_package_id: - remove_element(ident, refines) - metadata = XPath('./opf:metadata')(root)[0] - if new_application_id: - ident = metadata.makeelement(DC('identifier')) - ident.text = 'calibre:%s' % new_application_id - if package_identifier is None: - metadata.append(ident) - else: - p = package_identifier.getparent() - p.insert(p.index(package_identifier), ident) +def identifier_writer(name): + def writer(root, prefixes, refines, ival=None): + uid = root.get('unique-identifier') + package_identifier = None + for ident in XPath('./opf:metadata/dc:identifier')(root): + is_package_id = uid is not None and uid == ident.get('id') + if is_package_id: + package_identifier = ident + val = (ident.text or '').strip() + if (val.startswith(name + ':') or ident.get(OPF('scheme')) == name) and not is_package_id: + remove_element(ident, refines) + metadata = XPath('./opf:metadata')(root)[0] + if ival: + ident = metadata.makeelement(DC('identifier')) + ident.text = '%s:%s' % (name, ival) + if package_identifier is None: + metadata.append(ident) + else: + p = package_identifier.getparent() + p.insert(p.index(package_identifier), ident) + return writer +set_application_id = identifier_writer('calibre') +set_uuid = identifier_writer('uuid') # }}} @@ -786,7 +790,9 @@ def read_metadata(root): for key, vals in identifiers.iteritems(): if key == 'calibre': ans.application_id = vals[0] - elif key != 'uuid': + elif key == 'uuid': + ans.uuid = vals[0] + else: ids[key] = vals[0] ans.set_identifiers(ids) ans.title = read_title(root, prefixes, refines) or ans.title @@ -867,6 +873,11 @@ def apply_metadata(root, mi, cover_prefix='', cover_data=None, apply_null=False, set_author_link_map(root, prefixes, refines, getattr(mi, 'author_link_map', None)) if ok('user_categories'): set_user_categories(root, prefixes, refines, getattr(mi, 'user_categories', None)) + # We ignore apply_null for the next two to match the behavior with opf2.py + if mi.application_id: + set_application_id(root, prefixes, refines, mi.application_id) + if mi.uuid: + set_uuid(root, prefixes, refines, mi.uuid) new_user_metadata, current_user_metadata = mi.get_all_user_metadata(True), current_mi.get_all_user_metadata(True) missing = object() for key in tuple(new_user_metadata): diff --git a/src/calibre/ebooks/metadata/opf3_test.py b/src/calibre/ebooks/metadata/opf3_test.py index 244207ffad..5cd6cd8116 100644 --- a/src/calibre/ebooks/metadata/opf3_test.py +++ b/src/calibre/ebooks/metadata/opf3_test.py @@ -74,7 +74,7 @@ class TestOPF3(unittest.TestCase): root = self.get_opf(metadata=idt('a:1')+idt('a:2')+idt('calibre:x')+idt('uuid:y')) mi = read_metadata(root) self.ae(mi.application_id, 'x') - set_application_id(root, default_refines, 'y') + set_application_id(root, {}, default_refines, 'y') mi = read_metadata(root) self.ae(mi.application_id, 'y') @@ -86,7 +86,7 @@ class TestOPF3(unittest.TestCase): set_identifiers(root, read_prefixes(root), default_refines, {'i':'2', 'o':'2'}, force_identifiers=True) self.ae({'i':['2', '1'], 'o':['2']}, ri(root)) root = self.get_opf(metadata=idt('i:1', iid='uid') + idt('r:1') + idt('o:1')) - set_application_id(root, default_refines, 'y') + set_application_id(root, {}, default_refines, 'y') mi = read_metadata(root) self.ae(mi.application_id, 'y') # }}} @@ -478,23 +478,24 @@ class TestOPF3(unittest.TestCase): def compare_metadata(mi2, mi3): self.ae(mi2.get_all_user_metadata(False), mi3.get_all_user_metadata(False)) for field in ALL_METADATA_FIELDS: - if field in 'manifest uuid'.split(): - continue - v2, v3 = getattr(mi2, field, None), getattr(mi3, field, None) - self.ae(v2, v3, '%s: %r != %r' % (field, v2, v3)) + if field != 'manifest': + v2, v3 = getattr(mi2, field, None), getattr(mi3, field, None) + self.ae(v2, v3, '%s: %r != %r' % (field, v2, v3)) mi2 = OPF(BytesIO(raw.encode('utf-8'))).to_book_metadata() root = etree.fromstring(raw) root.set('version', '3.0') mi3 = read_metadata(root) compare_metadata(mi2, mi3) - apply_metadata(root, mi3) - compare_metadata(mi3, read_metadata(root)) + apply_metadata(root, mi3, force_identifiers=True) + nmi = read_metadata(root) + compare_metadata(mi3, nmi) mi3.tags = [] mi3.set('#tags', []) mi3.set('#number', 0) mi3.set('#commetns', '') - apply_metadata(root, mi3) + apply_metadata(root, mi3, update_timestamp=True) + self.assertFalse(root.xpath('//*/@name')) nmi = read_metadata(root) self.assertEqual(mi2.tags, nmi.tags) self.assertEqual(mi2.get('#tags'), nmi.get('#tags'))