Csv To Vcf -

def add_photo(self, contact: Dict, photo_path: str) -> str: """Add photo to vCard (base64 encoded)""" import base64 with open(photo_path, 'rb') as f: photo_data = base64.b64encode(f.read()).decode('utf-8') return f"PHOTO;ENCODING=b;TYPE=JPEG:photo_data"

try: count = converter.convert(args.input, args.output, args.encoding) print(f"\n✓ Conversion complete! count contacts converted.") return 0 except Exception as e: print(f"\n✗ Error: str(e)") return 1 if == " main ": exit(main()) 3. Installation Requirements # Install required package pip install chardet Or create requirements.txt echo "chardet>=5.0.0" > requirements.txt pip install -r requirements.txt 4. Usage Examples # Basic conversion python csv_to_vcf.py contacts.csv Specify output file python csv_to_vcf.py contacts.csv -o my_contacts.vcf Specify encoding for non-UTF8 files python csv_to_vcf.py contacts.csv -e iso-8859-1 In Python script from csv_to_vcf import CSVToVCFConverter csv to vcf

def create_vcf_card(self, contact: Dict, index: int) -> str: """Create single VCF card from contact data""" vcf_lines = [] # Begin vCard vcf_lines.append("BEGIN:VCARD") vcf_lines.append(f"VERSION:self.version") # Name (required) name = self.escape_vcf_text(contact.get('name', '')) if name: # Split name into parts name_parts = name.split(maxsplit=1) first_name = name_parts[0] if name_parts else '' last_name = name_parts[1] if len(name_parts) > 1 else '' vcf_lines.append(f"N:last_name;first_name;;;") vcf_lines.append(f"FN:name") else: vcf_lines.append(f"N:;;;index;") vcf_lines.append(f"FN:Contact index") # Phone number phone = self.format_phone(contact.get('phone', '')) if phone: vcf_lines.append(f"TEL;TYPE=CELL:phone") # Work phone (if available) work_phone = self.format_phone(contact.get('workphone', '')) if work_phone: vcf_lines.append(f"TEL;TYPE=WORK:work_phone") # Email email = self.escape_vcf_text(contact.get('email', '')) if email: vcf_lines.append(f"EMAIL;TYPE=INTERNET:email") # Company and Title company = self.escape_vcf_text(contact.get('company', '')) title = self.escape_vcf_text(contact.get('title', '')) if company: vcf_lines.append(f"ORG:company") if title: vcf_lines.append(f"TITLE:title") # Address address = self.escape_vcf_text(contact.get('address', '')) if address: vcf_lines.append(f"ADR;TYPE=WORK:;;address;;;;") # Website website = self.escape_vcf_text(contact.get('website', '')) if website: if not website.startswith(('http://', 'https://')): website = 'http://' + website vcf_lines.append(f"URL:website") # Birthday birthday = self.format_date(contact.get('birthday', '')) if birthday: vcf_lines.append(f"BDAY:birthday") # Notes notes = self.escape_vcf_text(contact.get('notes', '')) if notes: vcf_lines.append(f"NOTE:notes") # UID (unique identifier) import uuid vcf_lines.append(f"UID:uuid.uuid4()") # Revision date vcf_lines.append(f"REV:datetime.now().strftime('%Y%m%dT%H%M%SZ')") # End vCard vcf_lines.append("END:VCARD") vcf_lines.append("") # Empty line between cards return '\n'.join(vcf_lines) Usage Examples # Basic conversion python csv_to_vcf

def convert(self, input_file: str, output_file: Optional[str] = None, encoding: Optional[str] = None) -> int: """Convert CSV to VCF and save to file""" # Read CSV contacts = self.read_csv(input_file, encoding) if not contacts: print("No valid contacts found in CSV file") return 0 print(f"Found len(contacts) contacts") # Determine output filename if not output_file: input_path = Path(input_file) output_file = input_path.stem + '.vcf' # Write VCF file try: with open(output_file, 'w', encoding='utf-8') as f: for i, contact in enumerate(contacts, start=1): vcf_card = self.create_vcf_card(contact, i) f.write(vcf_card) if i < len(contacts): f.write('\n') print(f"Successfully converted len(contacts) contacts to output_file") return len(contacts) except Exception as e: raise Exception(f"Error writing VCF file: str(e)") index: int) -&gt

def format_phone(self, phone: str) -> str: """Format phone number for VCF""" if not phone: return "" # Remove spaces and common separators phone = re.sub(r'[\(\)\s\-\.]', '', phone) # Add international prefix if missing if phone.startswith('0') and not phone.startswith('+'): phone = '+1' + phone[1:] # Default to US/Canada, customize as needed return self.escape_vcf_text(phone)

with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f: f.write(csv_content) f.flush() result = self.converter.convert_to_string(f.name) self.assertIn("FN:John Doe", result) self.assertIn("TEL;TYPE=CELL:+1234567890", result) os.unlink(f.name)

def normalize_column_name(self, col: str) -> str: """Normalize column names to standard format""" col = col.lower().strip() mapping = 'name': 'name', 'fullname': 'name', 'displayname': 'name', 'phone': 'phone', 'mobile': 'phone', 'telephone': 'phone', 'cell': 'phone', 'workphone': 'phone', 'email': 'email', 'emailaddress': 'email', 'company': 'company', 'organization': 'company', 'title': 'title', 'jobtitle': 'title', 'position': 'title', 'address': 'address', 'street': 'address', 'website': 'website', 'url': 'website', 'webpage': 'website', 'birthday': 'birthday', 'bday': 'birthday', 'dob': 'birthday', 'notes': 'notes', 'comment': 'notes', 'description': 'notes' return mapping.get(col, col)