[PATCH eac] Add ParallelNames entity for <nameEntryParallel> tag

Frank Bessou frank.bessou at logilab.fr
Mon Aug 26 16:25:00 CEST 2019


Will apply, but I have a question and a suggestion below :)

On 26/08/2019 12:27, Guillaume Vandevelde wrote:
> # HG changeset patch
> # User Guillaume Vandevelde <gvandevelde at logilab.fr>
> # Date 1566290946 -7200
> #      Tue Aug 20 10:49:06 2019 +0200
> # Node ID 5ee1a2dcb62861282ce4694b99cb157636913176
> # Parent  f6c054166efd558f4af6acec52975827beefe9ad
> # Available At http://hg.logilab.org/review/cubes/eac
> #              hg pull http://hg.logilab.org/review/cubes/eac -r 5ee1a2dcb628
> Add  ParallelNames entity for <nameEntryParallel> tag
> 
> A hook have to be set on the NameEntry entity
> verifying that the same object can not have a
> `simple_name_relation` and a `name_entry_relation`
> 
> diff -r f6c054166efd -r 5ee1a2dcb628 cubicweb_eac/dataimport.py
> --- a/cubicweb_eac/dataimport.py	Thu Jul 25 14:36:52 2019 +0200
> +++ b/cubicweb_eac/dataimport.py	Tue Aug 20 10:49:06 2019 +0200
> @@ -46,8 +46,8 @@
>                        'Mandate', 'LegalStatus', 'History', 'HistoricalEvent', 'Structure',
>                        'AgentFunction', 'Occupation', 'GeneralContext', 'AssociationRelation',
>                        'ChronologicalRelation', 'HierarchicalRelation', 'EACResourceRelation',
> -                     'EACFunctionRelation', 'ExternalUri', 'EACSource', 'Activity',
> -                     'NameEntry')
> +                     'EACFunctionRelation', 'ParallelNames', 'ExternalUri', 'EACSource',
> +                     'Activity', 'NameEntry')

Isn't PlaceEntry missing from this list ?

>   
>   
>   class InvalidEAC(RuntimeError):
> @@ -193,6 +193,8 @@
>   
>   add_citations_for = partial(add_child_for, relation='has_citation', builder='build_citation')
>   add_events_for = partial(add_child_for, relation='has_event', builder='build_event')
> +add_names_for = partial(add_child_for, relation='simple_name_relation',
> +                        builder='build_name_child')
>   add_dates_for = partial(add_child_for, relation='date_relation',
>                           builder='build_date_entry')
>   add_place_entries_for = partial(add_child_for, relation='place_entry_relation',
> @@ -445,6 +447,20 @@
>               raise MissingTag('nameEntry', 'identity')
>           for name_entry in name_entries:
>               yield self.build_name_entry(name_entry)
> +        parallel_name_entries = self._elem_findall(identity, 'eac:nameEntryParallel')
> +        for parallel_name_entry in parallel_name_entries:
> +            for extentity in self.build_parallel(parallel_name_entry):
> +                yield extentity
> +
> +    @relate_to_record_through('ParallelNames', 'parallel_names_of')
> +    @add_names_for('ParallelNames')
> +    @add_dates_for('ParallelNames')
> +    def build_parallel(self, elem):
> +        """For each nameEntryParallel build a new object linked to the
> +        EAC-CPF document and get relations for all childrens"""
> +        values = self.values_from_xpaths(elem, (('authorized_form', 'eac:authorizedForm'),
> +                                                ('alternative_form', 'eac:alternativeForm')))
> +        yield ExtEntity('ParallelNames', self._gen_extid(), values)
>   
>       def extract_dates_from(self, elem, tag):
>           for date in self.find_nested(elem, 'eac:date', tag):
> @@ -464,6 +480,24 @@
>               for extentity in self.extract_dates_from(date_set, 'eac:dateSet'):
>                   yield extentity
>   
> +    @filter_empty
> +    @filter_none
> +    @elem_maybe_none
> +    def build_name_child(self, elem):
> +        """Build NameEntry external entity"""
> +        for elem in self._elem_findall(elem, 'eac:nameEntry'):
> +            values = self.values_from_attrib(elem, (('language', 'lang'),
> +                                                    ('script_code', 'scriptCode')))
> +            values.update(self.values_from_xpaths(elem,
> +                                                  (('preferred_form', 'eac:preferredForm'),
> +                                                   ('alternative_form', 'eac:alternativeForm'),
> +                                                   ('authorized_form', 'eac:authorizedForm'))))
> +            parts = self._elem_findall(elem, 'eac:part')
> +            if not parts:
> +                raise MissingTag('part', 'nameEntry')
> +            values.update({'parts': set([u', '.join(text_type(p.text) for p in parts)])})
I think that

values["parts"] = {u', '.join(text_type(p.text) for p in parts}

would be sufficient :)

> +            yield ExtEntity('NameEntry', self._gen_extid(), values)
> +
>       @filter_none
>       def parse_description(self, description):
>           """Parse the `description` tag and yield external entities, possibly
> diff -r f6c054166efd -r 5ee1a2dcb628 cubicweb_eac/entities.py
> --- a/cubicweb_eac/entities.py	Thu Jul 25 14:36:52 2019 +0200
> +++ b/cubicweb_eac/entities.py	Tue Aug 20 10:49:06 2019 +0200
> @@ -251,6 +251,12 @@
>                                                   'longitude', 'local_type'))
>   
>   
> +class ParallelNames(DateRelationMixin, AnyEntity):
> +    __regid__ = 'ParallelNames'
> +    fetch_attrs, cw_fetch_order = fetch_config(('authorized_form',
> +                                                'alternative_form'))
> +
> +
>   # XML export
>   
>   def substitute_xml_prefix(prefix_name, namespaces):
> diff -r f6c054166efd -r 5ee1a2dcb628 cubicweb_eac/migration/0.9.0_Any.py
> --- a/cubicweb_eac/migration/0.9.0_Any.py	Thu Jul 25 14:36:52 2019 +0200
> +++ b/cubicweb_eac/migration/0.9.0_Any.py	Tue Aug 20 10:49:06 2019 +0200
> @@ -1,5 +1,6 @@
>   add_entity_type('HistoricalEvent')
>   add_entity_type('Convention')
> +add_entity_type('ParallelNames')
>   add_entity_type('EACFunctionRelation')
>   add_entity_type('DateEntity')
>   add_entity_type('PlaceEntry')
> diff -r f6c054166efd -r 5ee1a2dcb628 cubicweb_eac/schema.py
> --- a/cubicweb_eac/schema.py	Thu Jul 25 14:36:52 2019 +0200
> +++ b/cubicweb_eac/schema.py	Tue Aug 20 10:49:06 2019 +0200
> @@ -79,17 +79,38 @@
>                             vocabulary=[_('authorized'), _('alternative')])
>   
>   
> +class ParallelNames(EntityType):
> +    authorized_form = String(fulltextindexed=True)
> +    alternative_form = String(fulltextindexed=True)
> +
> +
> +class simple_name_relation(RelationDefinition):
> +    subject = 'ParallelNames'
> +    object = 'NameEntry'
> +    cardinality = '*?'
> +    composite = 'subject'
> +    fulltext_container = 'subject'
> +
> +
> +class parallel_names_of(RelationDefinition):
> +    subject = 'ParallelNames'
> +    object = 'AuthorityRecord'
> +    cardinality = '1*'
> +    composite = 'object'
> +    fulltext_container = 'object'
> +
> +
>   class name_entry_for(RelationDefinition):
>       subject = 'NameEntry'
>       object = 'AuthorityRecord'
> -    cardinality = '1+'
> +    cardinality = '?+'
>       composite = 'object'
>       fulltext_container = 'object'
>       inlined = True
>   
>   
>   class date_relation(RelationDefinition):
> -    subject = ('HierarchicalRelation', 'HistoricalEvent',
> +    subject = ('ParallelNames', 'HierarchicalRelation', 'HistoricalEvent',
>                  'ChronologicalRelation', 'AssociationRelation',
>                  'AgentFunction', 'EACFunctionRelation', 'LegalStatus',
>                  'Mandate', 'Occupation', 'AgentPlace', 'EACResourceRelation')
> diff -r f6c054166efd -r 5ee1a2dcb628 test/data/FRAD033_EAC_00001_simplified.xml
> --- a/test/data/FRAD033_EAC_00001_simplified.xml	Thu Jul 25 14:36:52 2019 +0200
> +++ b/test/data/FRAD033_EAC_00001_simplified.xml	Tue Aug 20 10:49:06 2019 +0200
> @@ -119,7 +119,51 @@
>             <alternativeForm>conventionDeclaration</alternativeForm>
>   
>         </nameEntry>
> +      <nameEntryParallel>
> +	<nameEntry lang="fr" scriptCode="Latn">
> +	  <part>Institut international des droits de
> +	  l'homme
> +	  </part>
> +	  <preferredForm>AFNOR_Z44-060
> +	  </preferredForm>
> +	</nameEntry>
> +	<nameEntry lang="en" scriptCode="Latn">
> +	  <part>International institute of human
> +	  rights
> +	  </part>
> +	</nameEntry>
> +	<authorizedForm>AFNOR_Z44-060
> +	</authorizedForm>
> +      </nameEntryParallel>
> +      <nameEntryParallel>
> +	<nameEntry localType="authorized">
> +	  <part lang="eng"
> +		localType="corpname">Federal Chancellery
> +	  of Germany
> +	  </part>
> +	</nameEntry>
> +	<nameEntry localType="authorized">
> +	  <part lang="fre"
> +		localType="corpname">Chancellerie fédérale
> +	  d'Allemagne
> +	  </part>
> +	</nameEntry>
> +	<nameEntry localType="abbreviation">
> +	  <part lang="ger"
> +		localType="corpname">BK
> +	  </part>
> +	</nameEntry>
>   
> +	<useDates>
> +	  <dateRange localType="open">
> +	    <fromDate
> +		standardDate="1949">1949
> +	    </fromDate>
> +	    <toDate>open
> +	    </toDate>
> +	  </dateRange>
> +	  </useDates>	
> +	</nameEntryParallel>
>       </identity>
>   
>       <description>
> diff -r f6c054166efd -r 5ee1a2dcb628 test/test_dataimport.py
> --- a/test/test_dataimport.py	Thu Jul 25 14:36:52 2019 +0200
> +++ b/test/test_dataimport.py	Tue Aug 20 10:49:06 2019 +0200
> @@ -84,7 +84,7 @@
>           return importer.external_entities()
>   
>       def test_parse_FRAD033_EAC_00001(self):
> -        _gen_extid = map(str, (x for x in count() if x not in (2, 28))).next
> +        _gen_extid = map(str, (x for x in count() if x not in (2, 36))).next
>           expected = [
>               ('AuthorityRecord', 'FRAD033_EAC_00001',
>                {'isni': set([u'22330001300016']),
> @@ -189,6 +189,47 @@
>                 'name_entry_for': set(['FRAD033_EAC_00001']),
>                 },
>                ),
> +            ('ParallelNames', _gen_extid(),
> +             {'parallel_names_of': set(['FRAD033_EAC_00001']),
> +              'simple_name_relation': set(['15', '14']),
> +              'authorized_form': set([u'AFNOR_Z44-060\n\t'])
> +              },
> +             ),
> +            ('NameEntry', _gen_extid(),
> +             {'script_code': set([u'Latn']),
> +              'preferred_form': [u'AFNOR_Z44-060\n\t  '],
> +              'parts': set([u"Institut international des droits de\n\t  l'homme\n\t  "]),
> +              'language': set([u'fr'])
> +              },
> +             ),
> +            ('NameEntry', _gen_extid(),
> +             {'script_code': set([u'Latn']),
> +              'parts': set([u'International institute of human\n\t  rights\n\t  ']),
> +              'language': set([u'en'])
> +              },
> +             ),
> +            ('ParallelNames', _gen_extid(),
> +             {'parallel_names_of': set(['FRAD033_EAC_00001']),
> +              'date_relation': set(['17']),
> +              'simple_name_relation': set(['19', '18', '20'])
> +              },
> +             ),
> +            ('DateEntity', _gen_extid(),
> +             {'start_date': set([datetime.date(1949, 1, 1)])
> +              },
> +             ),
> +            ('NameEntry', _gen_extid(),
> +             {'parts': [u'Federal Chancellery\n\t  of Germany\n\t  ']
> +              },
> +             ),
> +            ('NameEntry', _gen_extid(),
> +             {'parts': [u"Chancellerie f\xe9d\xe9rale\n\t  d'Allemagne\n\t  "]
> +              },
> +             ),
> +            ('NameEntry', _gen_extid(),
> +             {'parts': set([u'BK\n\t  '])
> +              },
> +             ),
>               ('PostalAddress', _gen_extid(),
>                {'street': set([u'1 Esplanade Charles de Gaulle']),
>                 'postalcode': set([u'33074']),
> @@ -198,8 +239,8 @@
>               ('AgentPlace', _gen_extid(),
>                {'role': set([u'siege']),
>                 'place_agent': set(['FRAD033_EAC_00001']),
> -              'place_entry_relation': set(['15']),
> -              'place_address': set(['13']),
> +              'place_entry_relation': set(['23']),
> +              'place_address': set(['21']),
>                 },
>                ),
>               ('PlaceEntry', _gen_extid(),
> @@ -209,7 +250,7 @@
>                ),
>               ('AgentPlace', _gen_extid(),
>                {'place_agent': set(['FRAD033_EAC_00001']),
> -              'place_entry_relation': set(['17']),
> +              'place_entry_relation': set(['25']),
>                 'role': set([u'domicile']),
>                 },
>                ),
> @@ -223,7 +264,7 @@
>               ('AgentPlace', _gen_extid(),
>                {'place_agent': set(['FRAD033_EAC_00001']),
>                 'role': set([u'dodo']),
> -              'place_entry_relation': set(['19']),
> +              'place_entry_relation': set(['27']),
>                 },
>                ),
>               ('PlaceEntry', _gen_extid(),
> @@ -232,7 +273,7 @@
>                ),
>               ('LegalStatus', _gen_extid(),
>                {'term': set([u'Collectivité territoriale']),
> -              'date_relation': set(['21']),
> +              'date_relation': set(['29']),
>                 'description': set([u'Description du statut']),
>                 'description_format': set([u'text/plain']),
>                 'legal_status_agent': set(['FRAD033_EAC_00001']),
> @@ -252,6 +293,8 @@
>                ),
>               ('History', _gen_extid(),
>                {'abstract': set([u'Test of an abstract element']),
> +              'has_citation': set(['33', '32']),
> +              'has_event': set(['34', '35']),
>                 'text': set(["\n".join((
>                     u'<p xmlns="urn:isbn:1-931666-33-4" '
>                     u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
> @@ -272,8 +315,6 @@
>                               u'      (1931)\n\t    </li>\n\t  </ul>\n      ']),
>                 'items_format': set([u'text/html']),
>                 'history_agent': set(['FRAD033_EAC_00001']),
> -              'has_citation': set(['24', '25']),
> -              'has_event': set(['26', '27']),
>                 },
>                ),
>               ('Citation', _gen_extid(),
> @@ -334,11 +375,11 @@
>                ),
>               ('Occupation', _gen_extid(),
>                {'term': set([u'Réunioniste']),
> -              'date_relation': set(['34']),
> +              'date_relation': set(['42']),
>                 'description': set([u'Organisation des réunions ...']),
>                 'description_format': set([u'text/plain']),
>                 'occupation_agent': set(['FRAD033_EAC_00001']),
> -              'has_citation': set(['35']),
> +              'has_citation': set(['43']),
>                 'equivalent_concept': set(['http://pifgadget.com']),
>                 },
>                ),
> @@ -356,7 +397,7 @@
>                                 u'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
>                                 u'xmlns:xlink="http://www.w3.org/1999/xlink">very famous</p>']),
>                 'content_format': set([u'text/html']),
> -              'has_citation': set(['37']),
> +              'has_citation': set(['45']),
>                 'general_context_of': set(['FRAD033_EAC_00001']),
>                 }
>                ),
> @@ -372,7 +413,7 @@
>               ('HierarchicalRelation', _gen_extid(),
>                {'entry': set([u"Gironde. Conseil général. Direction de l'administration et de "
>                               u"la sécurité juridique"]),
> -              'date_relation': set(['39']),
> +              'date_relation': set(['47']),
>                 'description': set([u'Coucou']),
>                 'description_format': set([u'text/plain']),
>                 'hierarchical_parent': set(['CG33-DIRADSJ']),
> @@ -397,7 +438,7 @@
>               ('ChronologicalRelation', _gen_extid(),
>                {'chronological_predecessor': set(['whatever']),
>                 'chronological_successor': set(['FRAD033_EAC_00001']),
> -              'date_relation': set(['41']),
> +              'date_relation': set(['49']),
>                 'entry': set([u'CG32']),
>                 },
>                ),
> @@ -409,7 +450,7 @@
>               ('ChronologicalRelation', _gen_extid(),
>                {'chronological_predecessor': set(['FRAD033_EAC_00001']),
>                 'chronological_successor': set(['/dev/null']),
> -              'date_relation': set(['43']),
> +              'date_relation': set(['51']),
>                 'xml_wrap': set(['<gloups xmlns="urn:isbn:1-931666-33-4"'
>                                  u' xmlns:xsi="http://www.w3.org/2001/XML'
>                                  u'Schema-instance" xmlns:xlink="http://'
> @@ -428,7 +469,7 @@
>                ),
>               ('EACResourceRelation', _gen_extid(),
>                {'agent_role': set([u'creatorOf']),
> -              'date_relation': set(['46']),
> +              'date_relation': set(['54']),
>                 'xml_attributes': set([u'{"{http://www.w3.org/1999/xlink}actuate": "onRequest", '
>                                        u'"{http://www.w3.org/1999/xlink}show": "new", '
>                                        u'"{http://www.w3.org/1999/xlink}type": "simple"}']),
> @@ -490,7 +531,7 @@
>                                     'and abolishment of schools.\n\t  </p>']),
>                 'r_type': set([u'controls']),
>                 'description_format': set([u'text/html']),
> -              'date_relation': set(['49']),
> +              'date_relation': set(['57']),
>                 'relation_entry': set([u'Establishment and abolishment\n\tof schools\n\t']),
>                 'xml_attributes': set([u'{}'])
>                 },
> @@ -511,7 +552,7 @@
>                 'description_format': set([u'text/html']),
>                 'relation_entry': set([u'Some relation entry\n          ']),
>                 'xml_attributes': set([u'{}']),
> -              'date_relation': ['51'],
> +              'date_relation': ['59'],
>                 },
>                ),
>               ('DateEntity', _gen_extid(),
> @@ -530,7 +571,7 @@
>                 'description_format': set([u'text/html']),
>                 'relation_entry': set([u'Some relation entry\n          ']),
>                 'xml_attributes': set([u'{}']),
> -              'date_relation': ['53'],
> +              'date_relation': ['61'],
>                 },
>                ),
>               ('DateEntity', _gen_extid(),
> @@ -596,8 +637,8 @@
>                             'languageDeclaration': set([21]),
>                             'localControl': set([54]),
>                             'source': set([76]),  # empty.
> -                          'structureOrGenealogy': set([189]),  # empty.
> -                          'biogHist': set([249, 252]),  # empty.
> +                          'structureOrGenealogy': set([233]),  # empty.
> +                          'biogHist': set([293, 296]),  # empty.
>                             })
>   
>       def check_order_entities(self, entities, expected):
> @@ -741,7 +782,7 @@
>                                  cwuri=u'http://data.culture.fr/thesaurus/page/ark:/67717/T1-1074')
>               cnx.commit()
>               created, updated = testutils.eac_import(cnx, fpath)
> -            self.assertEqual(len(created), 63)
> +            self.assertEqual(len(created), 71)
>               self.assertEqual(updated, set())
>               rset = cnx.find('AuthorityRecord', isni=u'22330001300016')
>               self.assertEqual(len(rset), 1)
> @@ -766,7 +807,8 @@
>               self.assertEqual(len(record.reverse_function_agent), 3)
>               for related in ('structure', 'history', 'mandate', 'occupation',
>                               'generalcontext', 'legal_status', 'eac_relations',
> -                            'equivalent_concept', 'control', 'convention'):
> +                            'equivalent_concept', 'control', 'convention',
> +                            'parallel_relations'):
>                   with self.subTest(related=related):
>                       checker = getattr(self, '_check_' + related)
>                       checker(cnx, record)
> @@ -889,6 +931,18 @@
>           self.assertEqual(func_relation.function_relation_function[0].uri,
>                            u'FRAD033_IR_N')
>   
> +    def _check_parallel_relations(self, cnx, record):
> +        rset = cnx.find('ParallelNames', parallel_names_of=record).sorted_rset(lambda x: x.eid)
> +        self.assertEqual(len(rset), 2)
> +        p_entity = rset.get_entity(0, 0)
> +        self.assertEqual(p_entity.parallel_names_of[0], record)
> +        self.assertEqual(len(p_entity.simple_name_relation), 2)
> +        self.assertEqual(len(p_entity.date_relation), 0)
> +        p_entity = rset.get_entity(1, 0)
> +        self.assertEqual(p_entity.parallel_names_of[0], record)
> +        self.assertEqual(len(p_entity.simple_name_relation), 3)
> +        self.assertEqual(len(p_entity.date_relation), 1)
> +
>       def _check_equivalent_concept(self, cnx, record):
>           functions = dict((f.name, f) for f in record.reverse_function_agent)
>           self.assertEqual(functions['action sociale'].equivalent_concept[0].cwuri,
> diff -r f6c054166efd -r 5ee1a2dcb628 test/test_schema.py
> --- a/test/test_schema.py	Thu Jul 25 14:36:52 2019 +0200
> +++ b/test/test_schema.py	Tue Aug 20 10:49:06 2019 +0200
> @@ -105,7 +105,8 @@
>               ])},
>               'DateEntity': {('date_relation', 'object'): set([
>                   'HistoricalEvent', 'AgentFunction', 'EACFunctionRelation',
> -                'LegalStatus', 'Mandate', 'Occupation', 'AgentPlace', 'EACResourceRelation'
> +                'LegalStatus', 'Mandate', 'Occupation', 'AgentPlace', 'EACResourceRelation',
> +                'ParallelNames'
>               ])},
>               'PlaceEntry': {('place_entry_relation', 'object'): set([
>                   'HistoricalEvent', 'AgentFunction', 'EACFunctionRelation',
> @@ -124,8 +125,10 @@
>               'History': {('history_agent', 'subject'): set(['AuthorityRecord'])},
>               'LegalStatus': {('legal_status_agent', 'subject'): set(['AuthorityRecord'])},
>               'Mandate': {('mandate_agent', 'subject'): set(['AuthorityRecord'])},
> -            'NameEntry': {('name_entry_for', 'subject'): set(['AuthorityRecord'])},
> +            'NameEntry': {('name_entry_for', 'subject'): set(['AuthorityRecord']),
> +                          ('simple_name_relation', 'object'): set(['ParallelNames'])},
>               'Occupation': {('occupation_agent', 'subject'): set(['AuthorityRecord'])},
> +            'ParallelNames': {('parallel_names_of', 'subject'): set(['AuthorityRecord'])},
>               'PostalAddress': {('place_address', 'object'): set(['AgentPlace'])},
>               'Structure': {('structure_agent', 'subject'): set(['AuthorityRecord'])},
>           }
> @@ -138,7 +141,8 @@
>           graph = AuthorityRecordGraph(self.schema)
>           structure = graph.parent_structure('AuthorityRecord')
>           opts = optional_relations(self.schema, structure)
> -        expected = {}
> +        expected = {'NameEntry': set([('name_entry_for', 'subject'),
> +                                      ('simple_name_relation', 'object')])}
>           self.assertEqual(opts, expected)
>   
>       def test_relations_consistency(self):
> 

-- 
Frank Bessou
Logilab         https://www.logilab.fr



More information about the saem-devel mailing list