diff --git a/rero_ils/dojson/utils.py b/rero_ils/dojson/utils.py index 2b314204a9..727120d8c5 100644 --- a/rero_ils/dojson/utils.py +++ b/rero_ils/dojson/utils.py @@ -17,14 +17,18 @@ """Dojson utils.""" +import os import re import sys import traceback from copy import deepcopy import click +import requests from dojson import Overdo, utils +from rero_ils.modules.utils import requests_retry_session + _UNIMARC_LANGUAGES_SCRIPTS = { 'ba': 'latn', # Latin 'ca': 'cyrl', # Cyrillic @@ -286,6 +290,8 @@ 'z': 'Not applicable' } +_CONTRIBUTION_TAGS = ['100', '600', '610', '611', '630', '650', '651', + '655', '700', '710', '711'] re_identified = re.compile(r'\((.*)\)(.*)') @@ -379,6 +385,35 @@ def remove_trailing_punctuation( '', data.rstrip()).rstrip() +def get_contribution_link(bibid, reroid, id, key): + """Get MEF contribution link. + + :params bibid: Bib id from the record. + :params reroid: RERO id from the record. + :params id: $0 from the marc field. + :params key: Tag from the marc field. + :returns: MEF url. + """ + # https://mef.test.rero.ch/api/mef/?q=rero.rero_pid:A012327677 + prod_host = 'mef.rero.ch' + test_host = os.environ.get('RERO_ILS_MEF_HOST', 'mef.rero.ch') + mef_url = f'https://{test_host}/api/' + + match = re_identified.search(id) + if match and len(match.groups()) == 2 and key[:3] in _CONTRIBUTION_TAGS: + match_type = match.group(1).lower() + match_value = match.group(2) + if match_type == 'idref': + url = f'{mef_url}{match_type}/{match_value}' + response = requests_retry_session().get(url) + status_code = response.status_code + if status_code == requests.codes.ok: + return url.replace(test_host, prod_host) + error_print('WARNING GET MEF CONTRIBUTION:', + bibid, reroid, key, id, url, status_code) + else: + error_print('ERROR GET MEF CONTRIBUTION:', bibid, reroid, key, id) + def add_note(new_note, data): """Add a new note to the data avoiding duplicate notes. @@ -913,6 +948,7 @@ class ReroIlsMarc21Overdo(ReroIlsOverdo): has_field_490 = False has_field_580 = False content_media_carrier_type = None + links_from_752 = [] def __init__(self, bases=None, entry_point_group=None): """Reroilsmarc21overdo init.""" @@ -962,8 +998,11 @@ def do(self, blob, ignore_missing=True, exception_handlers=None): self.field_008_data = '' self.date1_from_008 = None self.date2_from_008 = None + self.original_date_from_008 = None self.date_type_from_008 = '' self.date = {'start_date': None} + self.serial_type = '' + self.is_top_level_record = False fields_008 = self.get_fields(tag='008') if fields_008: self.field_008_data = self.get_control_field_data( @@ -995,9 +1034,9 @@ def do(self, blob, ignore_missing=True, exception_handlers=None): # identifiy a top level record (has 019 $a Niveau supérieur) regexp = re.compile(r'Niveau sup[eé]rieur', re.IGNORECASE) fields_019 = self.get_fields(tag='019') - note = '' notes_from_019_and_351 = [] for field_019 in fields_019: + note = '' for subfield_a in self.get_subfields(field_019, 'a'): note += ' | ' + subfield_a if regexp.search(subfield_a): @@ -1037,7 +1076,20 @@ def do(self, blob, ignore_missing=True, exception_handlers=None): if description_conventions: self.admin_meta_data['descriptionConventions'] = \ description_conventions - # check presence of specific fields + + # build the list of links from filed 752 + self.links_from_752 = [] + fields_752 = self.get_fields(tag='752') + for field_752 in fields_752: + subfields_d = self.get_subfields(field_752, 'd') + items = get_field_items(field_752['subfields']) + + if subfields_d: + identifier = build_identifier(field_752['subfields']) + if identifier: + self.links_from_752.append(identifier) + + # check presence of specific fields self.has_field_490 = len(self.get_fields(tag='490')) > 0 self.has_field_580 = len(self.get_fields(tag='580')) > 0 result = super().do( @@ -1107,7 +1159,7 @@ def init_lang_from(fields_041, code): langs_from_041.append(lang_from_041) return langs_from_041 - self.lang_from_008 = '' + self.lang_from_008 = None self.langs_from_041_a = [] self.langs_from_041_h = [] try: diff --git a/rero_ils/modules/documents/dojson/contrib/marc21tojson/model.py b/rero_ils/modules/documents/dojson/contrib/marc21tojson/model.py index 66518073ce..088abd7824 100644 --- a/rero_ils/modules/documents/dojson/contrib/marc21tojson/model.py +++ b/rero_ils/modules/documents/dojson/contrib/marc21tojson/model.py @@ -17,20 +17,35 @@ """rero-ils MARC21 model definition.""" -import os import re -import requests from dojson import utils from dojson.utils import GroupableOrderedDict from rero_ils.dojson.utils import ReroIlsMarc21Overdo, TitlePartList, \ add_note, build_identifier, build_responsibility_data, \ build_string_from_subfields, error_print, \ - extract_subtitle_and_parallel_titles_from_field_245_b, get_field_items, \ - get_field_link_data, make_year, not_repetitive, re_identified, \ - remove_trailing_punctuation -from rero_ils.modules.utils import requests_retry_session + extract_subtitle_and_parallel_titles_from_field_245_b, \ + get_contribution_link, get_field_items, get_field_link_data, make_year, \ + not_repetitive, remove_trailing_punctuation + +_DOCUMENT_RELATION_PER_TAG = { + '770': 'supplement', + '772': 'supplementTo', + '775': 'otherEdition', + '776': 'otherPhysicalFormat', + '777': 'IssuedWith', + '780': 'precededBy', + '785': 'succeededBy', + '787': 'relatedTo', + '533': 'hasReproduction', + '534': 'reproductionOf' +} + +_REPRODUCTION_SUBFIELDS_PER_TAG = { + '533': 'abcdemn', + '534': 'cep' +} _ISSUANCE_MAIN_TYPE_PER_BIB_LEVEL = { 'a': 'rdami:1001', @@ -211,41 +226,21 @@ _IDREF_REF_REGEX = re.compile(r'^(?i)\(IdRef\)(.*)?') _RERO_REF_REGEX = re.compile(r'^(?i)\(RERO\)(.*)?') -_CONTRIBUTION_TAGS = ['100', '600', '610', '611', '630', '650', '651', - '655', '700', '710', '711'] - marc21 = ReroIlsMarc21Overdo() - -def get_contribution_link(bibid, reroid, id, key): - """Get MEF contribution link. - - :params bibid: Bib id from the record. - :params reroid: RERO id from the record. - :params id: $0 from the marc field. - :params key: Tag from the marc field. - :returns: MEF url. - """ - # https://mef.test.rero.ch/api/mef/?q=rero.rero_pid:A012327677 - prod_host = 'mef.rero.ch' - test_host = os.environ.get('RERO_ILS_MEF_HOST', 'mef.rero.ch') - mef_url = f'https://{test_host}/api/' - - match = re_identified.search(id) - if match and len(match.groups()) == 2 and key[:3] in _CONTRIBUTION_TAGS: - match_type = match.group(1).lower() - match_value = match.group(2) - if match_type == 'idref': - url = f'{mef_url}{match_type}/{match_value}' - response = requests_retry_session().get(url) - status_code = response.status_code - if status_code == requests.codes.ok: - return url.replace(test_host, prod_host) - error_print('WARNING GET MEF CONTRIBUTION:', - bibid, reroid, key, id, url, status_code) - else: - error_print('ERROR GET MEF CONTRIBUTION:', bibid, reroid, key, id) +def build_place(): + """Build place data for provisionActivity.""" + place = {} + if marc21.cantons: + place['canton'] = marc21.cantons[0] + if marc21.country: + place['country'] = marc21.country + if place: + place['type'] = 'bf:Place' + if marc21.links_from_752: + place['identifyBy'] = marc21.links_from_752[0] + return place @marc21.over('issuance', 'leader') @@ -346,7 +341,26 @@ def marc21_to_language(self, key, value): if fields_264: error_print('WARNING INVALID 264', marc21.bib_id, marc21.rero_id, fields_264) - self['provisionActivity'] = [{'type': 'bf:Publication'}] + places = [] + publication = { + 'type': 'bf:Publication' + } + place = build_place() + if place: + places.append(place) + # parce le link skipping the fist (already used by build_place) + for i in range(1, len(marc21.links_from_752)): + place = { + 'country': 'und', + 'type': 'bf:Place', + 'identifyBy': links_from_752[i] + } + places.append(place) + + if places: + publication['place'] = places + self['provisionActivity'] = [publication] + if (marc21.date_type_from_008 == 'q' or marc21.date_type_from_008 == 'n'): self['provisionActivity'][0][ @@ -635,6 +649,33 @@ def marc21_to_contribution(self, key, value): } +@marc21.over('relation', '(770|772|775|776|777|780|785|787|533|534)..') +@utils.for_each_value +@utils.ignore_value +def marc21_to_specific_document_relation(self, key, value): + """Get contribution.""" + tag = key[:3] + relation = None + if tag in ['533', '534']: + label = build_string_from_subfields( + value, + _REPRODUCTION_SUBFIELDS_PER_TAG[tag] + ) + relation = {'label': label} + else: + subfield_w = not_repetitive(marc21.bib_id, marc21.rero_id, + key, value, 'w', default='').strip() + if subfield_w: + match = re.compile(r'^REROILS:') + pid = match.sub('', subfield_w) + ref = f'https://bib.rero.ch/api/documents/{pid}' + relation = {'$ref': ref} + if relation: + relation_list = self.get(_DOCUMENT_RELATION_PER_TAG[tag], []) + relation_list.append(relation) + self[_DOCUMENT_RELATION_PER_TAG[tag]] = relation_list + + @marc21.over('copyrightDate', '^264.4') @utils.ignore_value def marc21_to_copyright_date(self, key, value): @@ -690,10 +731,12 @@ def marc21_to_edition_statement(self, key, value): def marc21_to_provisionActivity(self, key, value): """Get publisher data. + publisher.name: 264 [$b repetitive] (without the , but keep the ;) publisher.place: 264 [$a repetitive] (without the : but keep the ;) publicationDate: 264 [$c repetitive] (but take only the first one) """ + def build_statement(field_value, ind2): def build_agent_data(code, label, index, link): @@ -732,16 +775,6 @@ def build_agent_data(code, label, index, link): index += 1 return statement - def build_place(): - place = {} - if marc21.cantons: - place['canton'] = marc21.cantons[0] - if marc21.country: - place['country'] = marc21.country - if place: - place['type'] = 'bf:Place' - return place - # the function marc21_to_provisionActivity start here ind2 = key[4] type_per_ind2 = { @@ -763,9 +796,21 @@ def build_place(): publication['endDate'] = marc21.date['end_date'] if 'note' in marc21.date: publication['note'] = marc21.date['note'] + + places = [] place = build_place() if place: - publication['place'] = [place] + places.append(place) + # parce le link skipping the fist (already used by build_place) + for i in range(1, len(marc21.links_from_752)): + place = { + 'country': 'und', + 'type': 'bf:Place', + 'identifyBy': marc21.links_from_752[i] + } + places.append(place) + if places: + publication['place'] = places publication['statement'] = build_statement(value, ind2) if subfields_c: @@ -859,6 +904,47 @@ def marc21_to_summary(self, key, value): self['tableOfContents'] = table_of_contents_list +@marc21.over('usageAndAccessPolicy', '^(506|540)..') +@utils.ignore_value +def marc21_to_usage_and_access_policy_from_field_506_540(self, key, value): + """Get usageAndAccessPolicy from fields: 506, 540.""" + subfield_a = not_repetitive(marc21.bib_id, marc21.rero_id, + key, value, 'a', default='').strip() + if subfield_a: + policy = { + 'type': 'bf:UsageAndAccessPolicy', + 'label': subfield_a + } + usage_and_access_policy = self.get('usageAndAccessPolicy', []) + usage_and_access_policy.append(policy) + return usage_and_access_policy or None + + +@marc21.over('frequency', '^(310|321)..') +@utils.ignore_value +def marc21_to_frequency_field_310_321(self, key, value): + """Get frequency from fields: 310, 321.""" + subfield_a = not_repetitive( + marc21.bib_id, marc21.rero_id, + key, value, 'a', default='missing_label').strip() + subfield_b = not_repetitive( + marc21.bib_id, marc21.rero_id, + key, value, 'b', default='').strip() + + frequency = { + 'label': remove_trailing_punctuation( + data=subfield_a, + punctuation=',', + spaced_punctuation=',' + ) + } + if subfield_b: + frequency['date'] = subfield_b + frequency_list = self.get('frequency', []) + frequency_list.append(frequency) + return frequency_list or None + + @marc21.over('dissertation', '^502..') @utils.for_each_value @utils.ignore_value @@ -1308,7 +1394,7 @@ def marc21_to_identifiedBy_from_field_930(self, key, value): return identifiedBy or None -@marc21.over('note', '^(500|510|530|545|580)..') +@marc21.over('note', '^(500|510|530|545|555|580)..') @utils.for_each_value @utils.ignore_value def marc21_to_notes_and_original_title(self, key, value): diff --git a/tests/unit/test_documents_dojson.py b/tests/unit/test_documents_dojson.py index 7fa33d42d4..16867ada72 100644 --- a/tests/unit/test_documents_dojson.py +++ b/tests/unit/test_documents_dojson.py @@ -153,6 +153,41 @@ def test_marc21_to_admin_metadata(): 'note': ['Société de publications romanes (pf/08.05.1985)'], } + marc21xml = """ + + 00501naa a22001332a 4500 + 160315s2015 cc ||| | ||||00| |chi d + + Catalogué d'après la couverture + nebpun/12.2019 + + + BPUN: Sandoz, Pellet, Rosselet, Bähler + nebpun/12.2019 + + + !!!Bibliographie neuchâteloise!!! + necfbv/12.2019/3546 + + + !!! Discographie neuchâteloise!!! + necfbv/02.2021/3502 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('adminMetadata') == { + 'encodingLevel': 'Less-than-full level, material not examined', + 'note': [ + "Catalogué d'après la couverture (nebpun/12.2019)", + 'BPUN: Sandoz, Pellet, Rosselet, Bähler (nebpun/12.2019)', + '!!!Bibliographie neuchâteloise!!! (necfbv/12.2019/3546)', + '!!! Discographie neuchâteloise!!! (necfbv/02.2021/3502)' + ] + } + marc21xml = """ 00501naa a22001332a 4500 @@ -393,16 +428,16 @@ def test_marc21_to_mode_of_issuance(): marc21xml = """ - 00604cam a2200205 a 4500 + 01518ccm a2200337 a 4500 150707m20159999fr |||m|| ||||00|| 0fre d + "008">150414s1993 sz |||p|| |||| || 0fre d """ marc21json = create_record(marc21xml) data = marc21.do(marc21json) assert data.get('issuance') == { - 'main_type': 'rdami:1002', - 'subtype': 'set' + 'main_type': 'rdami:1001', + 'subtype': 'materialUnit' } @@ -1508,6 +1543,42 @@ def test_marc21_provisionActivity_without_264(): data = marc21.do(marc21json) assert data.get('provisionActivity') == [{ 'type': 'bf:Publication', + 'place': [{ + 'country': 'sz', + 'type': 'bf:Place' + }], + 'startDate': 2006, + 'endDate': 2010 + }] + + +def test_marc21_provisionActivity_without_264_with_752(): + """Test dojson publication statement. + + A value should be here even 264 does not exists. + """ + marc21xml = """ + + 070518s20062010sz ||| | ||||00| |fre d + + Neuchâtel (1450-1800, lieu d'édition ou d'impression) + (IdRef)027401421 + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('provisionActivity') == [{ + 'type': 'bf:Publication', + 'place': [{ + 'country': 'sz', + 'type': 'bf:Place', + 'identifyBy': { + 'type': 'IdRef', + 'value': '027401421' + } + }], 'startDate': 2006, 'endDate': 2010 }] @@ -1526,6 +1597,10 @@ def test_marc21_provisionActivity_with_original_date(): data = marc21.do(marc21json) assert data.get('provisionActivity') == [{ 'type': 'bf:Publication', + 'place': [{ + 'country': 'sz', + 'type': 'bf:Place' + }], 'startDate': 1997, 'original_date': 1849, 'endDate': 1849 @@ -1631,6 +1706,30 @@ def test_marc21_to_provisionActivity_canton(): } ] + marc21xml = """ + + 060831s1998 sz ||| | ||||00| |fre d + + sz + ch-vd + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('provisionActivity') == [ + { + 'type': 'bf:Publication', + 'place': [{ + 'canton': 'vd', + 'country': 'sz', + 'type': 'bf:Place' + }], + 'startDate': 1998 + } + ] + def test_marc21_to_provisionActivity_1_place_2_agents(): """Test dojson publication statement. @@ -1681,6 +1780,138 @@ def test_marc21_to_provisionActivity_1_place_2_agents(): ] +def test_marc21_to_provisionActivity_1_place_2_agents_with_one_752(): + """Test dojson publication statement. + - 1 publication place and 2 agents from one field 264 + - 1 field 752 + """ + + marc21xml = """ + + 940202m19699999fr |||||| ||||00|| |fre d + + [Paris] : + Desclée de Brouwer [puis] + Etudes augustiniennes, + 1969- + + + Neuchâtel (1450-1800, lieu d'édition ou d'impression) + (IdRef)027401421 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('provisionActivity') == [ + { + 'type': 'bf:Publication', + 'place': [{ + 'country': 'fr', + 'type': 'bf:Place', + 'identifyBy': { + 'type': 'IdRef', + 'value': '027401421' + } + }], + 'statement': [ + { + 'label': [{'value': '[Paris]'}], + 'type': 'bf:Place' + }, + { + 'label': [{'value': 'Desclée de Brouwer [puis]'}], + 'type': 'bf:Agent' + }, + { + 'label': [{'value': 'Etudes augustiniennes'}], + 'type': 'bf:Agent' + }, + { + 'label': [{'value': '1969-'}], + 'type': 'Date' + } + ], + 'startDate': 1969 + } + ] + + +def test_marc21_to_provisionActivity_1_place_2_agents_with_two_752(): + """Test dojson publication statement. + - 1 publication place and 2 agents from one field 264 + - 2 field 752 + """ + + marc21xml = """ + + 940202m19699999fr |||||| ||||00|| |fre d + + [Paris] : + Desclée de Brouwer [puis] + Etudes augustiniennes, + 1969- + + + Neuchâtel (1450-1800, lieu d'édition ou d'impression) + (IdRef)027401421 + + + Neuchâtel lieu d'édition ou d'impression) + (RERO)A000000001 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + print('T1000', data) + assert data.get('provisionActivity') == [ + { + 'type': 'bf:Publication', + 'place': [{ + 'country': 'fr', + 'type': 'bf:Place', + 'identifyBy': { + 'type': 'IdRef', + 'value': '027401421' + } + }, { + 'country': 'und', + 'type': 'bf:Place', + 'identifyBy': { + 'type': 'RERO', + 'value': 'A000000001' + } + } + ], + 'statement': [ + { + 'label': [{'value': '[Paris]'}], + 'type': 'bf:Place' + }, + { + 'label': [{'value': 'Desclée de Brouwer [puis]'}], + 'type': 'bf:Agent' + }, + { + 'label': [{'value': 'Etudes augustiniennes'}], + 'type': 'bf:Agent' + }, + { + 'label': [{'value': '1969-'}], + 'type': 'Date' + } + ], + 'startDate': 1969 + } + ] + + def test_marc21_to_provisionActivity_unknown_place_2_agents(): """Test dojson publication statement. - unknown place and 2 agents from one field 264 @@ -3047,8 +3278,8 @@ def test_marc21_to_notes_from_510(): ] -def test_marc21_to_notes_from_530_545_580(): - """Test dojson notes from field 530, 545 and 580 (L35).""" +def test_marc21_to_notes_from_530_545_555_580(): + """Test dojson notes from field 530, 545, 555 and 580 (L35).""" marc21xml = """ @@ -3058,6 +3289,9 @@ def test_marc21_to_notes_from_530_545_580(): note 545 + + note 555 + note 580 @@ -3071,6 +3305,9 @@ def test_marc21_to_notes_from_530_545_580(): }, { 'noteType': 'general', 'label': 'note 545' + }, { + 'noteType': 'general', + 'label': 'note 555' }, { 'noteType': 'general', 'label': 'note 580' @@ -3333,6 +3570,79 @@ def test_marc21_to_classification_from_980_2_brp_and_dr_sys(): ] +def test_marc21_to_frequency(): + """Test dojson frequency from field 310, 321 (L32).""" + + # field 310, 321 ok + marc21xml = """ + + + Annuel + 1982- + + + Irrégulier + 1953-1981 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('frequency') == [{ + 'label': 'Annuel', + 'date': '1982-' + }, { + 'label': 'Irrégulier', + 'date': '1953-1981' + } + ] + + # field 310 $a with trailing coma and missing $b, 321 ok + marc21xml = """ + + + Annuel, + + + Irrégulier + 1953-1981 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('frequency') == [{ + 'label': 'Annuel' + }, { + 'label': 'Irrégulier', + 'date': '1953-1981' + } + ] + + # field 310 ok, field 321 without $a + marc21xml = """ + + + Annuel + 1982- + + + 1953-1981 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('frequency') == [{ + 'label': 'Annuel', + 'date': '1982-' + }, { + 'label': 'missing_label', + 'date': '1953-1981' + } + ] + + def test_marc21_to_sequence_numbering_from_one_362(): """Test dojson sequence_numbering from 362 (L39).""" @@ -3391,6 +3701,61 @@ def test_marc21_to_table_of_contents_from_505(): ] +def test_marc21_to_usage_and_access_policy(): + """Test dojson usageAndAccessPolicy from field 506, 540 (L74).""" + + marc21xml = """ + + + Les archives de C. Roussopoulos + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('usageAndAccessPolicy') == [{ + 'type': 'bf:UsageAndAccessPolicy', + 'label': 'Les archives de C. Roussopoulos' + } + ] + + marc21xml = """ + + + Les archives de Carole Roussopoulos + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('usageAndAccessPolicy') == [{ + 'type': 'bf:UsageAndAccessPolicy', + 'label': 'Les archives de Carole Roussopoulos' + } + ] + + marc21xml = """ + + + Les archives de C. Roussopoulos + + + Les archives de Carole Roussopoulos + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('usageAndAccessPolicy') == [{ + 'type': 'bf:UsageAndAccessPolicy', + 'label': 'Les archives de C. Roussopoulos' + }, { + 'type': 'bf:UsageAndAccessPolicy', + 'label': 'Les archives de Carole Roussopoulos' + } + ] + + def test_marc21_to_credits_from_508(): """Test dojson credits from 508 (L41).""" @@ -3610,6 +3975,90 @@ def test_marc21_to_part_of(): }] +def test_marc21_to_specific_document_relation(): + """Test dojson for generation the specific document relations.""" + + # one 770 with link and one 770 without link + marc21xml = """ + + + Télé-top-Matin + REROILS:2000055 + + + Télé-top + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('supplement') == [{ + '$ref': 'https://bib.rero.ch/api/documents/2000055', + } + ] + # two 770 with link + marc21xml = """ + + + Télé-top-Matin + REROILS:2000055 + + + Télé-top + REROILS:2000056 + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('supplement') == [{ + '$ref': 'https://bib.rero.ch/api/documents/2000055', + }, { + '$ref': 'https://bib.rero.ch/api/documents/2000056', + } + ] + + marc21xml = """ + + + Master microfilm. + Lausanne : + BCU + 1998 + 1 bobine ; 35 mm + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('hasReproduction') == [{ + 'label': 'Master microfilm. Lausanne : BCU 1998 1 bobine ; 35 mm', + } + ] + + marc21xml = """ + + + Reproduction de l'édition de: + Paris : H. Champion, 1931 + + + Repro. sur microfilm: + Ed. de Minuit, 1968. - + 189 pages + + + """ + marc21json = create_record(marc21xml) + data = marc21.do(marc21json) + assert data.get('reproductionOf') == [{ + 'label': "Reproduction de l'édition de: Paris : H. Champion, 1931", + }, { + 'label': "Repro. sur microfilm: Ed. de Minuit, 1968. - 189 pages" + } + ] + + def test_marc21_to_part_of_without_link(): """Test dojson partOf when no link is specified.