text: from utils import CanadianScraper, CanadianPerson as Person
  
  import csv
  from io import StringIO
  
  COUNCIL_PAGE = 'https://www.assembly.ab.ca/txt/mla_home/contacts.csv'
  MEMBER_INDEX_URL = (
      'https://www.assembly.ab.ca/members/members-of-the-legislative-assembly'
  )
  
  PARTIES = {
      'AL': 'Alberta Liberal Party',
      'AP': 'Alberta Party',
      'IC': 'Independent Conservative',
      'IND': 'Independent',
      'FCP': 'Freedom Conservative Party',
      'ND': 'Alberta New Democratic Party',
      'NDP': 'Alberta New Democratic Party',
      'PC': 'Progressive Conservative Association of Alberta',
      'UC': 'United Conservative',
      'UCP': 'United Conservative Party',
      'W': 'Wildrose Alliance Party',
  }
  
  
  def get_party(abbr):
      """Return full party name from abbreviation"""
      return PARTIES[abbr]
  
  
  OFFICE_FIELDS = (
      'Address Type',
      'Address Line1',
      'Address Line2',
      'City',
      'Province',
      'Country',
      'Postal Code',
      'Phone Number',
      'Fax Number',
  )
  
  ADDRESS_FIELDS = (
      'Address Line1',
      'Address Line2',
      'City',
      'Province',
      'Country',
  )
  
  
  class AlbertaPersonScraper(CanadianScraper):
      def scrape(self):
          index = self.lxmlize(MEMBER_INDEX_URL)
          csv_text = self.get(COUNCIL_PAGE).text
          csv_text = '\n'.join(csv_text.split('\n')[3:])  # discard first 3 rows
          reader = csv.reader(StringIO(csv_text))
          # make unique field names for the two sets of address fields
          field_names = next(reader)
          for name in OFFICE_FIELDS:
              assert(field_names.count(name) == 2)
              field_names[field_names.index(name)] = '{} 1'.format(name)
              field_names[field_names.index(name)] = '{} 2'.format(name)
          rows = [dict(zip(field_names, row)) for row in reader]
          assert len(rows), 'No members found'
          for mla in rows:
              name = '{} {} {}'.format(
                  mla['MLA First Name'],
                  mla['MLA Middle Names'],
                  mla['MLA Last Name'],
              )
              if name.strip() == '':
                  continue
              party = get_party(mla['Caucus'])
              name_without_status = name.split(',')[0]
              row_xpath = '//td[normalize-space()="{}"]/..'.format(
                  mla['Constituency Name'],
              )
              detail_url, = index.xpath('{}//a/@href'.format(row_xpath))
              photo_url, = index.xpath('{}//img/@src'.format(row_xpath))
              p = Person(
                  primary_org='legislature',
                  name=name_without_status,
                  district=mla['Constituency Name'],
                  role='MLA',
                  party=party,
                  image=photo_url,
              )
              p.add_source(COUNCIL_PAGE)
              p.add_source(detail_url)
              if mla['Email']:
                  p.add_contact('email', mla['Email'])
              elif mla.get('MLA Email'):
                  p.add_contact('email', mla['MLA Email'])
              assert(mla['Address Type 1'] == 'Legislature Office')
              assert(mla['Address Type 2'] == 'Constituency Office')
  
              for suffix, note in ((1, 'legislature'), (2, 'constituency')):
                  for key, contact_type in (('Phone', 'voice'), ('Fax', 'fax')):
                      value = mla['{} Number {}'.format(key, suffix)]
                      if value and value != 'Pending':
                          p.add_contact(contact_type, value, note)
                  address = ', '.join(
                      filter(
                          bool, [
                              mla[
                                  '{} {}'.format(field, suffix)
                              ] for field in ADDRESS_FIELDS
                          ]
                      )
                  )
                  if address:
                      p.add_contact('address', address, note)
              yield p
  