# Module `Gnumed.business.gmVCard`

Import vCard data.

Expand source code

    # -*- coding: utf-8 -*-
    """Import vCard data."""
    #============================================================
    __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
    __license__ = "GPL v2"

    # std lib
    import sys
    import io
    import datetime as pyDT
    import logging

    # GNUmed
    if __name__ == '__main__':
            sys.path.insert(0, '../../')
            from Gnumed.pycommon import gmI18N
            gmI18N.activate_locale()
            gmI18N.install_domain()
    from Gnumed.pycommon import gmDateTime
    from Gnumed.business import gmPerson
    from Gnumed.business import gmDemographicRecord

    _log = logging.getLogger('gm-vcf')

    #============================================================
    def parse_vcard2dto(vc_text=None, filename=None):

            import vobject

            if vc_text is None:
                    _log.info('trying to parse vCard from [%s]', filename)
                    for encoding in ['utf8', 'Windows-1252']:
                            try:
                                    vcf = io.open(filename, mode = 'rt', encoding = encoding)
                                    vc_text = vcf.read()
                                    vcf.close()
                                    break
                            except UnicodeDecodeError:
                                    _log.exception('vCard not encoded as [%s]', encoding)
                    if vc_text is None:
                            return None
                    vcf_lines = []
                    found_first = False
                    for line in vc_text.split('\n'):
                            if not found_first:
                                    if line.strip() == 'BEGIN:VCARD':
                                            found_first = True
                                            vcf_lines.append(line)
                                    continue
                            vcf_lines.append(line)
                            if line.strip() == 'END:VCARD':
                                    break
                    vc_text = '\n'.join(vcf_lines)

            dob_format = '%Y%m%d'

            try:
                    vc = vobject.readOne(vc_text)
            except vobject.base.ParseError:
                    _log.exception('cannot parse, really a vcf ?')
                    return None

            try:
                    if vc.kind.value.strip() != 'individual':
                            _log.warning('not a vCard for a single person (vCard.KIND=%s)', vc.kind.value)
                            return None
            except AttributeError:
                    _log.debug('vCard.KIND attribute not available')

            dto = gmPerson.cDTO_person()
            dto.firstnames = vc.n.value.given.strip()
            dto.lastnames = vc.n.value.family.strip()
            try:
                    dto.title = vc.title.value.strip()
            except AttributeError:
                    _log.debug('vCard.TITLE attribute not available')
            try:
                    gender = vc.gender.value.strip().lower()
                    if gender != '':
                            dto.gender = gender
            except AttributeError:
                    _log.debug('vCard.GENDER attribute not available')
            try:
                    dob = pyDT.datetime.strptime(vc.bday.value.strip(), dob_format)
                    dto.dob = dob.replace(tzinfo = gmDateTime.pydt_now_here().tzinfo)
                    dto.dob_is_estimated = False
            except AttributeError:
                    _log.debug('vCard.BDAY attribute not available')
            dto.source = 'vCard %s' % vc.version.value.strip()

            adr = None
            try:
                    adr = vc.adr.value
            except AttributeError:
                    _log.debug('vCard.ADR attribute not available')
            if adr is not None:
                    region_code = None
                    region = adr.region.strip()
                    if region == '':
                            region = None
                    # deduce country
                    country_code = None
                    country = adr.country.strip()
                    if country == '':
                            country = None
                    if country is None:
                            country_row = gmDemographicRecord.map_urb_zip_region2country(urb = adr.city, zip = adr.code, region = region)
                            if country_row is not None:
                                    country = country_row['country']
                                    country_code = country_row['code_country']
                    else:
                            country_code = gmDemographicRecord.map_country2code(country = country)
                    if None in [country, country_code]:
                            _log.error('unknown vCard.ADR.country (%s), skipping address', adr.country)
                    else:
                            # deduce region
                            if region is None:
                                    region_row = gmDemographicRecord.map_urb_zip_country2region(urb = adr.city, zip = adr.code, country_code = country_code)
                                    if region_row is not None:
                                            region = region_row['region']
                                            region_code = region_row['code_region']
                            else:
                                    region_code = gmDemographicRecord.map_region2code(region = region, country_code = country_code)
                            if region_code is None:
                                    _log.warning('unknown vCard.ADR.region (%s), using default region', adr.region)
                            dto.remember_address (
                                    number = '?',
                                    street = adr.street,
                                    urb = adr.city,
                                    region_code = region_code,
                                    zip = adr.code,
                                    country_code = country_code,
                                    adr_type = 'home',
                                    subunit = None
                            )

            tel = None
            try:
                    tel = vc.tel.value
            except AttributeError:
                    _log.debug('vCard.TEL attribute not available')
            if tel is not None:
                    if 'TYPE' in vc.tel.params:
                            channel = (vc.tel.params['TYPE'][0]).lower()
                            if not channel.endswith('phone'):
                                    channel += 'phone'
                    else:
                            channel = 'homephone'
                    dto.remember_comm_channel(channel = channel, url = tel)

            email = None
            try:
                    email = vc.email.value
            except AttributeError:
                    _log.debug('vCard.EMAIL attribute not available')
            if email is not None:
                    dto.remember_comm_channel(channel = 'email', url = email)

            url = None
            try:
                    url = vc.url.value
            except AttributeError:
                    _log.debug('vCard.URL attribute not available')
            if url is not None:
                    dto.remember_comm_channel(channel = 'web', url = url)

            return dto

    #============================================================
    # main/testing
    #============================================================
    if __name__ == '__main__':

            if len(sys.argv) == 1:
                    sys.exit()

            if sys.argv[1] != 'test':
                    sys.exit()

            from Gnumed.pycommon import gmLog2

            gmDateTime.init()

            def test():
                    dto = parse_vcard2dto(filename = sys.argv[2])
                    print(dto)
                    print(dto.addresses)
                    print(dto.comm_channels)

            test()

## Functions

`def parse_vcard2dto(vc_text=None, filename=None)`
  Expand source code

      def parse_vcard2dto(vc_text=None, filename=None):

              import vobject

              if vc_text is None:
                      _log.info('trying to parse vCard from [%s]', filename)
                      for encoding in ['utf8', 'Windows-1252']:
                              try:
                                      vcf = io.open(filename, mode = 'rt', encoding = encoding)
                                      vc_text = vcf.read()
                                      vcf.close()
                                      break
                              except UnicodeDecodeError:
                                      _log.exception('vCard not encoded as [%s]', encoding)
                      if vc_text is None:
                              return None
                      vcf_lines = []
                      found_first = False
                      for line in vc_text.split('\n'):
                              if not found_first:
                                      if line.strip() == 'BEGIN:VCARD':
                                              found_first = True
                                              vcf_lines.append(line)
                                      continue
                              vcf_lines.append(line)
                              if line.strip() == 'END:VCARD':
                                      break
                      vc_text = '\n'.join(vcf_lines)

              dob_format = '%Y%m%d'

              try:
                      vc = vobject.readOne(vc_text)
              except vobject.base.ParseError:
                      _log.exception('cannot parse, really a vcf ?')
                      return None

              try:
                      if vc.kind.value.strip() != 'individual':
                              _log.warning('not a vCard for a single person (vCard.KIND=%s)', vc.kind.value)
                              return None
              except AttributeError:
                      _log.debug('vCard.KIND attribute not available')

              dto = gmPerson.cDTO_person()
              dto.firstnames = vc.n.value.given.strip()
              dto.lastnames = vc.n.value.family.strip()
              try:
                      dto.title = vc.title.value.strip()
              except AttributeError:
                      _log.debug('vCard.TITLE attribute not available')
              try:
                      gender = vc.gender.value.strip().lower()
                      if gender != '':
                              dto.gender = gender
              except AttributeError:
                      _log.debug('vCard.GENDER attribute not available')
              try:
                      dob = pyDT.datetime.strptime(vc.bday.value.strip(), dob_format)
                      dto.dob = dob.replace(tzinfo = gmDateTime.pydt_now_here().tzinfo)
                      dto.dob_is_estimated = False
              except AttributeError:
                      _log.debug('vCard.BDAY attribute not available')
              dto.source = 'vCard %s' % vc.version.value.strip()

              adr = None
              try:
                      adr = vc.adr.value
              except AttributeError:
                      _log.debug('vCard.ADR attribute not available')
              if adr is not None:
                      region_code = None
                      region = adr.region.strip()
                      if region == '':
                              region = None
                      # deduce country
                      country_code = None
                      country = adr.country.strip()
                      if country == '':
                              country = None
                      if country is None:
                              country_row = gmDemographicRecord.map_urb_zip_region2country(urb = adr.city, zip = adr.code, region = region)
                              if country_row is not None:
                                      country = country_row['country']
                                      country_code = country_row['code_country']
                      else:
                              country_code = gmDemographicRecord.map_country2code(country = country)
                      if None in [country, country_code]:
                              _log.error('unknown vCard.ADR.country (%s), skipping address', adr.country)
                      else:
                              # deduce region
                              if region is None:
                                      region_row = gmDemographicRecord.map_urb_zip_country2region(urb = adr.city, zip = adr.code, country_code = country_code)
                                      if region_row is not None:
                                              region = region_row['region']
                                              region_code = region_row['code_region']
                              else:
                                      region_code = gmDemographicRecord.map_region2code(region = region, country_code = country_code)
                              if region_code is None:
                                      _log.warning('unknown vCard.ADR.region (%s), using default region', adr.region)
                              dto.remember_address (
                                      number = '?',
                                      street = adr.street,
                                      urb = adr.city,
                                      region_code = region_code,
                                      zip = adr.code,
                                      country_code = country_code,
                                      adr_type = 'home',
                                      subunit = None
                              )

              tel = None
              try:
                      tel = vc.tel.value
              except AttributeError:
                      _log.debug('vCard.TEL attribute not available')
              if tel is not None:
                      if 'TYPE' in vc.tel.params:
                              channel = (vc.tel.params['TYPE'][0]).lower()
                              if not channel.endswith('phone'):
                                      channel += 'phone'
                      else:
                              channel = 'homephone'
                      dto.remember_comm_channel(channel = channel, url = tel)

              email = None
              try:
                      email = vc.email.value
              except AttributeError:
                      _log.debug('vCard.EMAIL attribute not available')
              if email is not None:
                      dto.remember_comm_channel(channel = 'email', url = email)

              url = None
              try:
                      url = vc.url.value
              except AttributeError:
                      _log.debug('vCard.URL attribute not available')
              if url is not None:
                      dto.remember_comm_channel(channel = 'web', url = url)

              return dto