docs: def _get_exposure(fname, stop=None):
      """
      :param fname:
          path of the XML file containing the exposure
      :param stop:
          node at which to stop parsing (or None)
      :returns:
          a pair (Exposure instance, list of asset nodes)
      """
      [exposure] = nrml.read(fname, stop=stop)
      if not exposure.tag.endswith('exposureModel'):
          raise InvalidFile('%s: expected exposureModel, got %s' %
                            (fname, exposure.tag))
      description = exposure.description
      try:
          conversions = exposure.conversions
      except AttributeError:
          conversions = Node('conversions', nodes=[Node('costTypes', [])])
      try:
          inslimit = conversions.insuranceLimit
      except AttributeError:
          inslimit = Node('insuranceLimit', text=True)
      try:
          deductible = conversions.deductible
      except AttributeError:
          deductible = Node('deductible', text=True)
      try:
          area = conversions.area
      except AttributeError:
          # NB: the area type cannot be an empty string because when sending
          # around the CostCalculator object we would run into this numpy bug
          # about pickling dictionaries with empty strings:
          # https://github.com/numpy/numpy/pull/5475
          area = Node('area', dict(type='?'))
      try:
          occupancy_periods = exposure.occupancyPeriods.text or ''
      except AttributeError:
          occupancy_periods = ''
      try:
          tagNames = exposure.tagNames
      except AttributeError:
          tagNames = Node('tagNames', text='')
      tagnames = ~tagNames or []
      if set(tagnames) & {'taxonomy', 'exposure', 'country'}:
          raise InvalidFile('taxonomy, exposure and country are reserved names '
                            'you cannot use it in <tagNames>: %s' % fname)
      tagnames.insert(0, 'taxonomy')
  
      # read the cost types and make some check
      cost_types = []
      retrofitted = False
      for ct in conversions.costTypes:
          with context(fname, ct):
              ctname = ct['name']
              if ctname == 'structural' and 'retrofittedType' in ct.attrib:
                  if ct['retrofittedType'] != ct['type']:
                      raise ValueError(
                          'The retrofittedType %s is different from the type'
                          '%s' % (ct['retrofittedType'], ct['type']))
                  if ct['retrofittedUnit'] != ct['unit']:
                      raise ValueError(
                          'The retrofittedUnit %s is different from the unit'
                          '%s' % (ct['retrofittedUnit'], ct['unit']))
                  retrofitted = True
              cost_types.append(
                  (ctname, valid.cost_type_type(ct['type']), ct['unit']))
      if 'occupants' in cost_types:
          cost_types.append(('occupants', 'per_area', 'people'))
      cost_types.sort(key=operator.itemgetter(0))
      cost_types = numpy.array(cost_types, cost_type_dt)
      insurance_limit_is_absolute = il = inslimit.get('isAbsolute')
      deductible_is_absolute = de = deductible.get('isAbsolute')
      cc = CostCalculator(
          {}, {}, {},
          True if de is None else de,
          True if il is None else il,
          {name: i for i, name in enumerate(tagnames)},
      )
      for ct in cost_types:
          name = ct['name']  # structural, nonstructural, ...
          cc.cost_types[name] = ct['type']  # aggregated, per_asset, per_area
          cc.area_types[name] = area['type']
          cc.units[name] = ct['unit']
      assets = []
      asset_refs = []
      exp = Exposure(
          exposure['id'], exposure['category'],
          description.text, cost_types, occupancy_periods,
          insurance_limit_is_absolute, deductible_is_absolute, retrofitted,
          area.attrib, assets, asset_refs, cc, TagCollection(tagnames))
      assets_text = exposure.assets.text.strip()
      if assets_text:
          # the <assets> tag contains a list of file names
          dirname = os.path.dirname(fname)
          exp.datafiles = [os.path.join(dirname, f) for f in assets_text.split()]
      else:
          exp.datafiles = []
      return exp, exposure.assets