docs: def parse_wiod(path, year=None, names=('isic', 'c_codes'),
                 popvector=None):
      """ Parse the wiod source files for the IOSystem
  
      WIOD provides the MRIO tables in excel - format (xlsx) at
      http://www.wiod.org/new_site/database/wiots.htm (release November 2013).
      To use WIOD in pymrio these (for the year of analysis) must be downloaded.
      The interindustry matrix of these files gets parsed in IOSystem.Z, the
      additional information is included as factor_input extension (value
      added,...)
  
      The folder with these xslx must than be passed to the WIOD parsing
      function. This folder may contain folders with the extension data. Every
      folder within the wiod root folder will be parsed for extension data and
      will be added to the IOSystem. The WIOD database offers the download of
      the environmental extensions as zip files. These can be read directly by
      the parser. In case a zip file and a folder with the same name are
      available, the data is read from the folder. If the zip files are
      extracted into folder, the folders must have the same name as the
      corresponding zip file (without the 'zip' extension).
  
      If a WIOD SEA file is present (at the root of path or in a folder named
      'SEA' - only one file!), the labor data of this file gets included in the
      factor_input extension (calculated for the the three skill levels
      available). The monetary data in this file is not added because it is only
      given in national currency.
  
      Since the "World Input-Output Tables in previous years' prices" are still
      under construction (20141129), no parser for these is provided.
  
      Some of the meta-parameter of the IOSystem are set automatically based on
      the values given in the first four cells and the name of the WIOD data
      files (base year, version, price, iosystem).
      These can be overwritten afterwards if needed.
  
      Parameters
      ----------
      path : string or pathlib.Path
          Path to the folder with the WIOD source files. In case that the path
          to a specific file is given, only this will be parsed irrespective of
          the values given in year.
      year : int or str
          Which year in the path should be parsed. The years can be given with
          four or two digits (eg [2012 or 12]). If the given path contains a
          specific file, the value of year will not be used (but inferred from
          the meta data)- otherwise it must be given For the monetary data the
          parser searches for files with 'wiot - two digit year'.
      names : string or tuple, optional
          WIOD provides three different sector/final demand categories naming
          schemes. These can can be specified for the IOSystem. Pass:
  
              1) 'isic': ISIC rev 3 Codes - available for interindustry flows
                 and final demand rows.
              2) 'full': Full names - available for final demand rows and
                 final demand columns (categories) and interindustry flows.
              3) 'c_codes' : WIOD specific sector numbers, available for final
                 demand rows and columns (categories) and interindustry flows.
  
          Internally, the parser relies on 1) for the interindustry flows and 3)
          for the final demand categories. This is the default and will also be
          used if just 'isic' gets passed ('c_codes' also replace 'isic' if this
          was passed for final demand categories). To specify different finial
          consumption category names, pass a tuple with (sectors/interindustry
          classification, fd categories), eg ('isic', 'full'). Names are case
          insensitive and passing the first character is sufficient.
      TODO popvector : TO BE IMPLEMENTED (consistent with EXIOBASE)
  
      Yields
      -------
      IOSystem
  
      Raises
      ------
      ParserError
          If the WIOD source file are not complete or inconsistent
  
      """
  
      # Path manipulation, should work cross platform
      path = os.path.abspath(os.path.normpath(str(path)))
  
      # wiot start and end
      wiot_ext = '.xlsx'
      wiot_start = 'wiot'
  
      # determine which wiod file to be parsed
      if not os.path.isdir(path):
          # 1. case - one file specified in path
          if os.path.isfile(path):
              wiot_file = path
          else:
              # just in case the ending was forgotten
              wiot_file = path + wiot_ext
      else:
          # 2. case: directory given-build wiot_file with the value given in year
          if not year:
              raise ParserError('No year specified '
                                '(either specify a specific file '
                                'or a path and year)')
          year_two_digit = str(year)[-2:]
          wiot_file_list = [fl for fl in os.listdir(path)
                            if (fl[:6] == wiot_start + year_two_digit and
                            os.path.splitext(fl)[1] == wiot_ext)]
          if len(wiot_file_list) != 1:
              raise ParserError('Multiple files for a given year or file not '
                                'found (specify a specific file in paramters)')
  
          wiot_file = os.path.join(path, wiot_file_list[0])
  
      wiot_file = wiot_file
      root_path = os.path.split(wiot_file)[0]
      if not os.path.exists(wiot_file):
          raise ParserError('WIOD file not found in the specified folder.')
  
      meta_rec = MRIOMetaData(location=root_path)
  
      # wiot file structure
      wiot_meta = {
              'col': 0,   # column of the meta information
              'year': 0,  # rest: rows with the data
              'iosystem': 2,
              'unit': 3,
              'end_row': 4,
              }
      wiot_header = {
              # the header indexes are the same for rows after removing the first
              # two lines (wiot_empty_top_rows)
              'code': 0,
              'sector_names': 1,
              'region': 2,
              'c_code': 3,
              }
      wiot_empty_top_rows = [0, 1]
  
      wiot_marks = {   # special marks
          'last_interindsec': 'c35',     # last sector of the interindustry
          'tot_facinp': ['r60', 'r69'],  # useless totals to remove from factinp
          'total_column': [-1],          # the total column in the whole data
          }
  
      wiot_sheet = 0   # assume the first one is the one with the data.
  
      # Wiod has an unfortunate file structure with overlapping metadata and
      # header. In order to deal with that first the full file is read.
      wiot_data = pd.read_excel(wiot_file,
                                sheet_name=wiot_sheet,
                                header=None)
  
      meta_rec._add_fileio('WIOD data parsed from {}'.format(wiot_file))
      # get meta data
      wiot_year = wiot_data.iloc[wiot_meta['year'], wiot_meta['col']][-4:]
      wiot_iosystem = wiot_data.iloc[
              wiot_meta['iosystem'], wiot_meta['col']].rstrip(')').lstrip('(')
      meta_rec.change_meta('system', wiot_iosystem)
      _wiot_unit = wiot_data.iloc[
              wiot_meta['unit'], wiot_meta['col']].rstrip(')').lstrip('(')
  
      # remove meta data, empty rows, total column
      wiot_data.iloc[0:wiot_meta['end_row'], wiot_meta['col']] = np.NaN
      wiot_data.drop(wiot_empty_top_rows,
                     axis=0, inplace=True)
      wiot_data.drop(wiot_data.columns[wiot_marks['total_column']],
                     axis=1, inplace=True)
      # at this stage row and column header should have the same size but
      # the index starts now at two - replace/reset to row numbers
      wiot_data.index = range(wiot_data.shape[0])
  
      # Early years in WIOD tables have a different name for Romania:
      # 'ROM' which should be 'ROU'. The latter is also consistent with
      # the environmental extensions names.
      wiot_data.iloc[wiot_header['region'], :] = wiot_data.iloc[
          wiot_header['region'], :].str.replace('ROM', 'ROU')
      wiot_data.iloc[:, wiot_header['region']] = wiot_data.iloc[
          :, wiot_header['region']].str.replace('ROM', 'ROU')
  
      # get the end of the interindustry matrix
      _lastZcol = wiot_data[
          wiot_data.iloc[
              :, wiot_header['c_code']] == wiot_marks['last_interindsec']
          ].index[-1]
      _lastZrow = wiot_data[
          wiot_data[wiot_header['c_code']] == wiot_marks['last_interindsec']
          ].index[-1]
  
      if _lastZcol != _lastZrow:
          raise ParserError(
              'Interindustry matrix not symetric in the WIOD source file')
      else:
          Zshape = (_lastZrow, _lastZcol)
  
      # separate factor input extension and remove
      # totals in the first and last row
      facinp = wiot_data.iloc[Zshape[0]+1:, :]
      facinp = facinp.drop(
          facinp[facinp[wiot_header['c_code']].isin(
              wiot_marks['tot_facinp'])].index, axis=0
          )
  
      Z = wiot_data.iloc[:Zshape[0]+1, :Zshape[1]+1].copy()
      Y = wiot_data.iloc[:Zshape[0]+1, Zshape[1]+1:].copy()
      F_fac = facinp.iloc[:, :Zshape[1]+1].copy()
      FY_fac = facinp.iloc[:, Zshape[1]+1:].copy()
  
      index_wiot_headers = [nr for nr in wiot_header.values()]
      # Save lookup of sectors and codes - to be used at the end of the parser
      # Assuming USA is present in every WIOT year
      wiot_sector_lookup = wiot_data[
          wiot_data[wiot_header['region']] == 'USA'].iloc[
              :, 0:max(index_wiot_headers)+1].applymap(str)
      wiot_sector_lookup.columns = [
          entry[1] for entry in sorted(
              zip(wiot_header.values(), wiot_header.keys()))]
      wiot_sector_lookup.set_index('code', inplace=True, drop=False)
      _Y = Y.T.iloc[:, [
          wiot_header['code'],  # Included to be consistent with  wiot_header
          wiot_header['sector_names'],
          wiot_header['region'],
          wiot_header['c_code'],
          ]]
      wiot_fd_lookup = _Y[_Y.iloc[
          :, wiot_header['region']] == 'USA'].applymap(str)
      wiot_fd_lookup.columns = [
          entry[1] for entry in
          sorted(zip(wiot_header.values(), wiot_header.keys()))]
      wiot_fd_lookup.set_index('c_code', inplace=True, drop=False)
      wiot_fd_lookup.index.name = 'code'
  
      # set the index/columns, work with code b/c these are also used in the
      # extensions
      Z[wiot_header['code']] = Z[wiot_header['code']].astype(str)
      Z.set_index([wiot_header['region'],
                  wiot_header['code']], inplace=True, drop=False)
      Z = Z.iloc[max(index_wiot_headers)+1:, max(index_wiot_headers)+1:]
      Z.index.names = IDX_NAMES['Z_col']
      Z.columns = Z.index
  
      indexY_col_head = Y.iloc[[wiot_header['region'],
                                wiot_header['c_code']], :]
      Y.columns = pd.MultiIndex.from_arrays(indexY_col_head.values,
                                            names=IDX_NAMES['Y_col2'])
      Y = Y.iloc[max(index_wiot_headers)+1:, :]
      Y.index = Z.index
  
      F_fac.set_index([wiot_header['sector_names']],
                      inplace=True, drop=False)  # c_code missing, use names
      F_fac.index.names = ['inputtype']
      F_fac = F_fac.iloc[:, max(index_wiot_headers)+1:]
      F_fac.columns = Z.columns
      FY_fac.columns = Y.columns
      FY_fac.index = F_fac.index
  
      # convert from object to float (was object because mixed float,str)
      Z = Z.astype('float')
      Y = Y.astype('float')
      F_fac = F_fac.astype('float')
      FY_fac = FY_fac.astype('float')
  
      # save the units
      Z_unit = pd.DataFrame(Z.iloc[:, 0])
      Z_unit.columns = ['unit']
      Z_unit['unit'] = _wiot_unit
  
      F_fac_unit = pd.DataFrame(F_fac.iloc[:, 0])
      F_fac_unit.columns = ['unit']
      F_fac_unit['unit'] = _wiot_unit
  
      ll_countries = list(Z.index.get_level_values('region').unique())
  
      # Finalize the factor inputs extension
      ext = dict()
  
      ext['factor_inputs'] = {'F': F_fac,
                              'FY': FY_fac,
                              'year': wiot_year,
                              'iosystem': wiot_iosystem,
                              'unit': F_fac_unit,
                              'name': 'factor input',
                              }
  
      # SEA extension
      _F_sea_data, _F_sea_unit = __get_WIOD_SEA_extension(
                              root_path=root_path, year=year)
      if _F_sea_data is not None:
          # None if no SEA file present
          _FY_sea = pd.DataFrame(index=_F_sea_data.index,
                                 columns=FY_fac.columns, data=0)
          _FY_sea = _FY_sea.astype('float')
  
          ext['SEA'] = {'F': _F_sea_data,
                        'FY': _FY_sea,
                        'year': wiot_year,
                        'iosystem': wiot_iosystem,
                        'unit': _F_sea_unit,
                        'name': 'SEA',
                        }
          meta_rec._add_fileio('SEA file extension parsed from {}'.format(
              root_path))
  
      # Environmental extensions, names follow the name given
      # in the meta sheet (except for CO2 to get a better description).
      # Units are hardcoded if no consistent place to read them
      # within the files (for all extensions in upper case).
      # The units names must exactly match!
      # Start must identify exactly one folder or a zip file to
      # read the extension.
      # Within the folder, the routine looks for xls files
      # starting with the country code.
      dl_envext_para = {
              'AIR': {'name': 'Air Emission Accounts',
                      'start': 'AIR_',
                      'ext': '.xls',
                      'unit': {
                              'CO2': 'Gg',
                              'CH4': 't',
                              'N2O': 't',
                              'NOx': 't',
                              'SOx': 't',
                              'CO': 't',
                              'NMVOC': 't',
                              'NH3': 't',
                              },
                      },
              'CO2': {'name': 'CO2 emissions - per source',
                      'start': 'CO2_',
                      'ext': '.xls',
                      'unit': {
                          'all': 'Gg'}
                      },
  
              'EM': {'name': 'Emission relevant energy use',
                     'start': 'EM_',
                     'ext': '.xls',
                     'unit': {
                          'all': 'TJ'}
                     },
              'EU': {'name': 'Gross energy use',
                     'start': 'EU_',
                     'ext': '.xls',
                     'unit': {
                          'all': 'TJ'}
                     },
              'lan': {'name': 'land use',
                      'start': 'lan_',
                      'ext': '.xls',
                      'unit': {
                          'all': None}
                      },
              'mat': {'name': 'material use',
                      'start': 'mat_',
                      'ext': '.xls',
                      'unit': {
                          'all': None}
                      },
              'wat': {'name': 'water use',
                      'start': 'wat_',
                      'ext': '.xls',
                      'unit': {
                          'all': None}
                      },
              }
  
      _FY_template = pd.DataFrame(columns=FY_fac.columns)
      _ss_FY_pressure_column = 'c37'
      for ik_ext in dl_envext_para:
          _dl_ex = __get_WIOD_env_extension(root_path=root_path,
                                            year=year,
                                            ll_co=ll_countries,
                                            para=dl_envext_para[ik_ext])
          if _dl_ex is not None:
              # None if extension not available
              _FY = _dl_ex['FY']
  
              _FY.columns = pd.MultiIndex.from_product([
                                  _FY.columns, [_ss_FY_pressure_column]])
              _FY = _FY_template.append(_FY)
              _FY.fillna(0, inplace=True)
              _FY.index.names = _dl_ex['F'].index.names
              _FY.columns.names = _FY_template.columns.names
              _FY = _FY[ll_countries]
              _FY = _FY.astype('float')
  
              ext[ik_ext] = {
                      'F': _dl_ex['F'],
                      'FY': _FY,
                      'year': wiot_year,
                      'iosystem': wiot_iosystem,
                      'unit': _dl_ex['unit'],
                      'name': dl_envext_para[ik_ext]['name'],
                      }
              meta_rec._add_fileio('Extension {} parsed from {}'.format(
                  ik_ext, root_path))
  
      # Build system
      wiod = IOSystem(Z=Z, Y=Y,
                      unit=Z_unit,
                      meta=meta_rec,
                      **ext)
  
      # Replace sector/final demand category names
      if type(names) is str:
          names = (names, names)
      ll_names = [w[0].lower() for w in names]
  
      if ll_names[0] == 'c':
          dd_sec_rename = wiot_sector_lookup.c_code.to_dict()
      elif ll_names[0] == 'i':
          dd_sec_rename = wiot_sector_lookup.code.to_dict()
      elif ll_names[0] == 'f':
          dd_sec_rename = wiot_sector_lookup.sector_names.to_dict()
      else:
          dd_sec_rename = wiot_sector_lookup.code.to_dict()
          warnings.warn('Parameter for names not understood - '
                        'used ISIC codes as sector names')
  
      if ll_names[1] == 'c':
          dd_fd_rename = wiot_fd_lookup.c_code.to_dict()
      elif ll_names[1] == 'i':
          dd_fd_rename = wiot_fd_lookup.c_code.to_dict()
      elif ll_names[1] == 'f':
          dd_fd_rename = wiot_fd_lookup.sector_names.to_dict()
      else:
          warnings.warn('Parameter for names not understood - '
                        'used c_codes as final demand category names')
  
      wiod.Z.rename(columns=dd_sec_rename, index=dd_sec_rename, inplace=True)
      wiod.Y.rename(columns=dd_fd_rename, index=dd_sec_rename, inplace=True)
      for ext in wiod.get_extensions(data=True):
          ext.F.rename(columns=dd_sec_rename, inplace=True)
          ext.FY.rename(columns=dd_fd_rename, inplace=True)
  
      return wiod