[PATCH 08 of 14 eac] Add support for <maintenanceAgency> <maintenanceStatus> <publicationStatus> and <functionRelation>

Guillaume Vandevelde guillaume.vandevelde at logilab.fr
Tue Jul 2 14:53:57 CEST 2019


# HG changeset patch
# User Guillaume Vandevelde <gvandevelde at logilab.fr>
# Date 1561390644 -7200
#      Mon Jun 24 17:37:24 2019 +0200
# Node ID f79eb89597e6db8a371861a1895453323607a9b7
# Parent  56aa0f4aa6eda5018e0d9c1a8190d3ec4fe44293
# Available At http://hg.logilab.org/review/cubes/eac
#              hg pull http://hg.logilab.org/review/cubes/eac -r f79eb89597e6
Add support for <maintenanceAgency> <maintenanceStatus> <publicationStatus> and <functionRelation>

Add the support for <functionRelation>, based on the schema for <ressourceRelation>. Also modified the schema of `MaintenanceAg` to support 2 new values. Some refacto are present also.

More tests have to be done, to check the new relationships.

Differential Revision: https://phab.logilab.fr/D3583

diff -r 56aa0f4aa6ed -r f79eb89597e6 cubicweb_eac/dataimport.py
--- a/cubicweb_eac/dataimport.py	Fri Jun 21 17:24:12 2019 +0200
+++ b/cubicweb_eac/dataimport.py	Mon Jun 24 17:37:24 2019 +0200
@@ -43,8 +43,8 @@
                      'Convention', 'LanguageDec', 'AgentPlace', 'MaintenanceAg', 'Mandate',
                      'LegalStatus', 'History', 'Event', 'Structure', 'AgentFunction', 'Occupation',
                      'GeneralContext', 'AssociationRelation', 'ChronologicalRelation',
-                     'HierarchicalRelation', 'EACResourceRelation', 'ExternalUri',
-                     'EACSource', 'Activity')
+                     'HierarchicalRelation', 'EACResourceRelation', 'EACFunctionRelation',
+                     'ExternalUri', 'EACSource', 'Activity')
 
 
 class InvalidEAC(RuntimeError):
@@ -295,6 +295,10 @@
         self.record = ExtEntity('AuthorityRecord', None, {})
         # Store a mapping of XML elements to produced ExtEntities
         self._visited = {}
+        self.valid_maintenance_status = set(['cancelled', 'deleted', 'deletedMerged',
+                                             'deletedReplaced', 'deletedSplit', 'derived',
+                                             'new', 'revised'])
+        self.valid_publication_status = set(['inProcess', 'approved', 'published'])
 
     def __getattribute__(self, name):
         attr = super(EACCPFImporter, self).__getattribute__(name)
@@ -302,6 +306,18 @@
             return trace_extentity(self)(attr)
         return attr
 
+    def check_maintenance_status(self, status):
+        if status and status in self.valid_maintenance_status:
+            return True
+        else:
+            return False
+
+    def check_publication_status(self, status):
+        if status and status in self.valid_publication_status:
+            return True
+        else:
+            return False
+
     def values_from_xpaths(self, elem, name_path_tuples, values={}):
         """build a `values` dict from xpath requests"""
         finder = partial(self._elem_find, elem)
@@ -779,14 +795,13 @@
         relations = self._elem_find(cpf_description, 'eac:relations')
         if relations is None:
             return
-        # cpfRelation.
-        for cpfrel in self._elem_findall(relations, 'eac:cpfRelation'):
-            for extentity in self.build_relation(cpfrel):
-                yield extentity
-        # resourceRelation.
-        for rrel in self._elem_findall(relations, 'eac:resourceRelation'):
-            for extentity in self.build_resource_relation(rrel):
-                yield extentity
+        builders = (('eac:cpfRelation', self.build_relation),
+                    ('eac:resourceRelation', self.build_resource_relation),
+                    ('eac:functionRelation', self.build_function_relation),)
+        for xpath, builder in builders:
+            for elem in self._elem_findall(relations, xpath):
+                for extentity in builder(elem):
+                    yield extentity
 
     @add_xml_wrap_for('AssociationRelation', 'ChronologicalRelation',
                       'HierarchicalRelation')
@@ -845,6 +860,41 @@
         values.update(self.parse_tag_description(elem))
         yield ExtEntity(etype, self._gen_extid(), values)
 
+    @add_xml_wrap_for('EACFunctionRelation')
+    def build_function_relation(self, elem):
+        """Build a relation between function entities"""
+        relationship = elem.attrib.get('functionRelationType')
+        if relationship is None:
+            self.import_log.record_warning(self._(
+                'found no functionRelationType attribute in element %s, defaulting '
+                'to performs') % etree.tostring(elem),
+                line=elem.sourceline)
+            relationship = 'performs'
+        obj_uri = elem.attrib.get('{%(xlink)s}href' % self.namespaces)
+        if obj_uri is None:
+            self.import_log.record_warning(self._(
+                'found a functionRelation without any object (no xlink:href '
+                'attribute), skipping'), line=elem.sourceline)
+            return
+        yield external_uri(obj_uri)
+        values = self.parse_tag_description(elem)
+        dates = self.parse_daterange(
+            self._elem_find(elem, 'eac:dateRange'))
+        if dates:
+            values.update(dates)
+        values.update({
+            'r_type': set([text_type(relationship)]),
+            'function_relation_function': set([text_type(obj_uri)]),
+            'function_relation_agent': set([text_type(self.record.extid)]),
+        })
+        new_values = self.values_from_xpaths(
+            elem,
+            (('place_entry', 'eac:placeEntry'),
+             ('relation_entry', 'eac:relationEntry')),
+            values)
+        #import pdb; pdb.set_trace()
+        yield ExtEntity('EACFunctionRelation', self._gen_extid(), new_values)
+
     @add_xml_wrap_for('EACResourceRelation')
     def build_resource_relation(self, elem):
         """Build a `EACResourceRelation` external entity (along with
@@ -896,9 +946,17 @@
                 extentity = ExtEntity('EACOtherRecordId', self._gen_extid(), values)
                 self.record_visited(other_record_id, extentity)
                 yield extentity
+        publication_status = self._elem_find(control, 'eac:publicationStatus')
+        p_status = publication_status.text.strip()
+        maintenance_status = self._elem_find(control, 'eac:maintenanceStatus')
+        if maintenance_status is None:
+            raise MissingTag('maintenanceStatus', 'control')
+        m_status = maintenance_status.text.strip()
         maintenance_agency = self._elem_find(control, 'eac:maintenanceAgency')
+        if maintenance_agency is None:
+            raise MissingTag('maintenanceAgency', 'control')
         if maintenance_agency is not None:
-            yield next(self.build_maintenance_agency(maintenance_agency))
+            yield next(self.build_maintenance_agency(maintenance_agency, m_status, p_status))
         builders = (('eac:sources/eac:source', self.build_source),
                     ('eac:maintenanceHistory/eac:maintenanceEvent', self.build_maintenance_event),
                     ('eac:languageDeclaration', self.build_language_declaration),
@@ -939,7 +997,7 @@
     @relate_to_record_through('MaintenanceAg', 'agency_of')
     @filter_empty
     @elem_maybe_none
-    def build_maintenance_agency(self, elem):
+    def build_maintenance_agency(self, elem, m_status, p_status):
         """Build a `MaintenanceAg` external entity"""
         desc_value = self.parse_tag_description(elem)
         values = self.values_from_xpaths(
@@ -948,6 +1006,10 @@
              ('agency_name', 'eac:agencyName'),
              ('other_agency_code', 'eac:otherAgencyCode')),
             desc_value)
+        if self.check_maintenance_status(m_status):
+            values.update({'maintenance_status': set([text_type(m_status)])})
+        if self.check_publication_status(p_status):
+            values.update({'publication_status': set([text_type(p_status)])})
         yield ExtEntity('MaintenanceAg', self._gen_extid(), values)
 
     @relate_to_record_through('LanguageDec', 'language_declaration_of')
diff -r 56aa0f4aa6ed -r f79eb89597e6 cubicweb_eac/migration/0.9.0_Any.py
--- a/cubicweb_eac/migration/0.9.0_Any.py	Fri Jun 21 17:24:12 2019 +0200
+++ b/cubicweb_eac/migration/0.9.0_Any.py	Mon Jun 24 17:37:24 2019 +0200
@@ -3,3 +3,6 @@
 add_entity_type('Convention')
 add_entity_type('LanguageDec')
 add_entity_type('MaintenanceAg')
+add_attribute('MaintenanceAg', 'maintenance_status')
+add_attribute('MaintenanceAg', 'publication_status')
+add_entity_type('EACFunctionRelation')
diff -r 56aa0f4aa6ed -r f79eb89597e6 cubicweb_eac/schema.py
--- a/cubicweb_eac/schema.py	Fri Jun 21 17:24:12 2019 +0200
+++ b/cubicweb_eac/schema.py	Mon Jun 24 17:37:24 2019 +0200
@@ -292,6 +292,8 @@
     agency_name = String(fulltextindexed=True)
     description = RichString(fulltextindexed=True)
     other_agency_code = String(fulltextindexed=True)
+    maintenance_status = String(fulltextindexed=True)
+    publication_status = String(fulltextindexed=True)
 
 
 class Convention(EntityType):
@@ -400,6 +402,35 @@
 
 @xml_wrap
 @dated_entity_type
+class EACFunctionRelation(EntityType):
+    """Represent a relation between an AuthorityRecord and a function"""
+    r_type = String(internationalizable=True,
+                    description=_('type of relation the function has '
+                                  'with the Authority'))
+    description = RichString(fulltextindexed=True)
+    relation_entry = String(fulltextindexed=True)
+    place_entry = String(fulltextindexed=True)
+    attributes = String(fulltextindexed=True)
+
+
+class function_relation_agent(RelationDefinition):
+    subject = 'EACFunctionRelation'
+    object = 'AuthorityRecord'
+    cardinality = '1*'
+    inlined = True
+    composite = 'object'
+    fulltext_container = 'object'
+
+
+class function_relation_function(RelationDefinition):
+    subject = 'EACFunctionRelation'
+    object = 'ExternalUri'
+    cardinality = '1*'
+    inlined = True
+
+
+ at xml_wrap
+ at dated_entity_type
 class EACResourceRelation(EntityType):
     """Represent a relation between an AuthorityRecord and a remote resource in the
     EAC-CPF model.
diff -r 56aa0f4aa6ed -r f79eb89597e6 test/data/FRAD033_EAC_00001_simplified.xml
--- a/test/data/FRAD033_EAC_00001_simplified.xml	Fri Jun 21 17:24:12 2019 +0200
+++ b/test/data/FRAD033_EAC_00001_simplified.xml	Mon Jun 24 17:37:24 2019 +0200
@@ -261,7 +261,6 @@
       </cpfRelation>
 
       <cpfRelation cpfRelationType="associative" xlink:href="agent-x" xlink:type="simple"></cpfRelation>
-
       <resourceRelation resourceRelationType="creatorOf"
         xmlns:xlink="http://www.w3.org/1999/xlink" 
         xlink:href="http://gael.gironde.fr/ead.html?id=FRAD033_IR_N" xlink:type="simple" xlink:role="Fonds d'archives" xlink:show="new" xlink:actuate="onRequest">
@@ -271,7 +270,60 @@
           <toDate>1963</toDate>
         </dateRange>
       </resourceRelation>
-      
+      <functionRelation
+	  functionRelationType="performs"
+	  xlink:href="http://gael.gironde.fr/ead.html?id=FRAD033_IR_N">
+	<relationEntry>Alumni communication
+	management, University of
+	Glasgow
+	</relationEntry>
+	<descriptiveNote>
+	  <p>The management of the University's
+	  communication with its alumni.
+	  </p>
+	</descriptiveNote>
+	<objectXMLWrap>
+	  <mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://www.loc.gov/mods/v3 http:
+				    //www.loc.gov/mods/v3/mods-3-3.xsd">
+	    <titleInfo>
+	      <title>Artisti trentini tra le due
+	      guerre
+	      </title>
+	    </titleInfo>
+	    <name>
+	      <namePart
+		  type="given">Nicoletta
+	      </namePart>
+	      <namePart
+		  type="family">Boschiero
+	      </namePart>
+	      <role>
+		<roleTerm
+		    type="text">autore
+		</roleTerm>
+	      </role>
+	    </name>
+	  </mods>
+	</objectXMLWrap>
+      </functionRelation>
+      <functionRelation
+	  functionRelationType="controls"
+	  xlink:href="FRAD033_IR_N">
+	<dateRange>
+          <fromDate standardDate="1922">1922</fromDate>
+          <toDate standardDate="2001">2001</toDate>
+          </dateRange>
+	<relationEntry>Establishment and abolishment
+	of schools
+	</relationEntry>
+	<descriptiveNote>
+	  <p>The second responsibility of the
+	  Department is to control the establishment
+	  and abolishment of schools.
+	  </p>
+	</descriptiveNote>
+      </functionRelation>
       
     </relations>
 
diff -r 56aa0f4aa6ed -r f79eb89597e6 test/data/custom_kind.xml
--- a/test/data/custom_kind.xml	Fri Jun 21 17:24:12 2019 +0200
+++ b/test/data/custom_kind.xml	Mon Jun 24 17:37:24 2019 +0200
@@ -6,6 +6,15 @@
   xmlns:xlink="http://www.w3.org/1999/xlink">
   <control>
     <recordId>FRAD033_EAC_00001</recordId>
+    <maintenanceStatus>new</maintenanceStatus>
+
+    <publicationStatus>approved</publicationStatus>
+
+    <maintenanceAgency>
+      <agencyCode>FR-AD033</agencyCode>
+      <!-- Problème dans les identifiants des services d'archives : l'EAC-CPF ne prend que la forme FR-ADXXX -->
+      <agencyName>Gironde. Archives départementales</agencyName>
+    </maintenanceAgency>
   </control>
 
   <cpfDescription>
diff -r 56aa0f4aa6ed -r f79eb89597e6 test/data/no_name_entry.xml
--- a/test/data/no_name_entry.xml	Fri Jun 21 17:24:12 2019 +0200
+++ b/test/data/no_name_entry.xml	Mon Jun 24 17:37:24 2019 +0200
@@ -4,6 +4,15 @@
          xsi:schemaLocation="urn:isbn:1-931666-33-4 http://eac.staatsbibliothek-berlin.de/schema/cpf.xsd"
          xmlns="urn:isbn:1-931666-33-4">
   <control>
+    <maintenanceStatus>new</maintenanceStatus>
+
+    <publicationStatus>approved</publicationStatus>
+
+    <maintenanceAgency>
+      <agencyCode>FR-AD033</agencyCode>
+      <!-- Problème dans les identifiants des services d'archives : l'EAC-CPF ne prend que la forme FR-ADXXX -->
+      <agencyName>Gironde. Archives départementales</agencyName>
+    </maintenanceAgency>
     <recordId>FRAD033_EAC_00001</recordId>
   </control>
   <cpfDescription>
diff -r 56aa0f4aa6ed -r f79eb89597e6 test/data/no_name_entry_part.xml
--- a/test/data/no_name_entry_part.xml	Fri Jun 21 17:24:12 2019 +0200
+++ b/test/data/no_name_entry_part.xml	Mon Jun 24 17:37:24 2019 +0200
@@ -5,6 +5,15 @@
          xmlns="urn:isbn:1-931666-33-4">
   <control>
     <recordId>FRAD033_EAC_00001</recordId>
+    <maintenanceStatus>new</maintenanceStatus>
+
+    <publicationStatus>approved</publicationStatus>
+
+    <maintenanceAgency>
+      <agencyCode>FR-AD033</agencyCode>
+      <!-- Problème dans les identifiants des services d'archives : l'EAC-CPF ne prend que la forme FR-ADXXX -->
+      <agencyName>Gironde. Archives départementales</agencyName>
+    </maintenanceAgency>
   </control>
   <cpfDescription>
     <identity>
diff -r 56aa0f4aa6ed -r f79eb89597e6 test/test_dataimport.py
--- a/test/test_dataimport.py	Fri Jun 21 17:24:12 2019 +0200
+++ b/test/test_dataimport.py	Mon Jun 24 17:37:24 2019 +0200
@@ -89,7 +89,9 @@
             ('MaintenanceAg', _gen_extid(),
              {'agency_of': ['FRAD033_EAC_00001'],
               'agency_name': set([u'Gironde. Archives d\xe9partementales']),
-              'agency_code': set([u'FR-AD033'])},
+              'agency_code': set([u'FR-AD033']),
+              'maintenance_status': set([u'new']),
+              'publication_status': set([u'approved'])},
             ),
             ('EACSource', _gen_extid(),
              {'source_agent': set(['FRAD033_EAC_00001']),
@@ -354,6 +356,41 @@
               'xml_wrap': set(['<he xmlns="urn:isbn:1-931666-33-4" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">joe</he>']),  # noqa
              },
             ),
+            ('EACFunctionRelation', _gen_extid(),
+             {'description': set([u'<p xmlns="urn:isbn:1-931666-33-4" xmlns:xsi="http:/'
+                                  '/www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http:'
+                                  '//www.w3.org/1999/xlink">The management of the University'
+                                  '\'s\n\t  communication with its alumni.\n\t  </p>']),
+              'r_type': [u'performs'],
+              'description_format': set([u'text/html']),
+              'function_relation_agent': set([u'FRAD033_EAC_00001']),
+              'function_relation_function': set([u'http://gael.gironde.fr/ead.html?'
+                                                 'id=FRAD033_IR_N']),
+              'relation_entry': set([u'Alumni communication\n\tmanagement, '
+                                     'University of\n\tGlasgow\n\t']),
+              'xml_wrap': ['<mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:isbn:1-931666-33-4" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.loc.gov/mods/v3 http:         //www.loc.gov/mods/v3/mods-3-3.xsd">\n\t    <titleInfo>\n\t      <title>Artisti trentini tra le due\n\t      guerre\n\t      </title>\n\t    </titleInfo>\n\t    <name>\n\t      <namePart type="given">Nicoletta\n\t      </namePart>\n\t      <namePart type="family">Boschiero\n\t      </namePart>\n\t      <role>\n\t\t<roleTerm type="text">autore\n\t\t</roleTerm>\n\t      </role>\n\t    </name>\n\t  </mods>\n\t'], # noqa
+             },
+            ),
+            ('EACFunctionRelation', _gen_extid(),
+             {'function_relation_function': set([u'FRAD033_IR_N']),
+              'function_relation_agent': set([u'FRAD033_EAC_00001']),
+              'description': set([u'<p xmlns="urn:isbn:1-931666-33-4" '
+                                  'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
+                                  'xmlns:xlink="http://www.w3.org/1999/xlink">'
+                                  'The second responsibility of the\n\t  '
+                                  'Department is to control the establishment\n\t  '
+                                  'and abolishment of schools.\n\t  </p>']),
+              'end_date': set([datetime.date(2001, 1, 1)]),
+              'r_type': set([u'controls']),
+              'description_format': set([u'text/html']),
+              'relation_entry': set([u'Establishment and abolishment\n\tof schools\n\t']),
+              'start_date': set([datetime.date(1922, 1, 1)])
+             },
+            ),
+            ('ExternalUri', 'FRAD033_IR_N',
+             {'uri': set([u'FRAD033_IR_N']),
+              'cwuri': set([u'FRAD033_IR_N'])},
+            ),
             ('ExternalUri', 'http://gael.gironde.fr/ead.html?id=FRAD033_IR_N',
              {'uri': set([u'http://gael.gironde.fr/ead.html?id=FRAD033_IR_N']),
               'cwuri': set([u'http://gael.gironde.fr/ead.html?id=FRAD033_IR_N'])},
@@ -507,7 +544,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), 47)
+            self.assertEqual(len(created), 50)
             self.assertEqual(updated, set())
             rset = cnx.find('AuthorityRecord', isni=u'22330001300016')
             self.assertEqual(len(rset), 1)
@@ -542,6 +579,16 @@
                                                     format=u'text/plain').strip(),
                          u'Pour accomplir ses missions ...')
 
+    def check_maintenance_agency(self, cnx, record):
+        rset = cnx.find('MaintenanceAg', structure_agent=record)
+        self.assertEqual(len(rset), 1)
+        self.assertEqual(rset.one().printable_value('agency_name',
+                                                    format=u'text/plain').strip(),
+                         set([u'Gironde. Archives d\xe9partementales']))
+        self.assertEqual(rset.one().printable_value('agency_code',
+                                                    format=u'text/plain').strip(),
+                         set([u'FR-AD033']))
+
     def _check_convention(self, cnx, record):
         rset = cnx.find('History', convention_of=record)
         self.assertEqual(len(rset), 3)
diff -r 56aa0f4aa6ed -r f79eb89597e6 test/test_schema.py
--- a/test/test_schema.py	Fri Jun 21 17:24:12 2019 +0200
+++ b/test/test_schema.py	Mon Jun 24 17:37:24 2019 +0200
@@ -103,6 +103,8 @@
                 'GeneralContext', 'Mandate', 'Occupation', 'AgentFunction',
                 'AgentPlace', 'History', 'LegalStatus', 'Convention',
             ])},
+            'EACFunctionRelation': {('function_relation_agent', 'subject'):
+                                    set(['AuthorityRecord'])},
             'EACOtherRecordId': {('eac_other_record_id_of', 'subject'):
                                  set(['AuthorityRecord'])},
             'EACResourceRelation': {('resource_relation_agent', 'subject'):


More information about the saem-devel mailing list