From acc7ac3098512c6d5a90c65c2124dde6fc837191 Mon Sep 17 00:00:00 2001 From: Juan Rodriguez Date: Sat, 15 Apr 2023 09:30:08 +0200 Subject: [PATCH 1/3] refactor: default_input_file_format + first_name, last_name, full_name new keys --- csv2vcf.py | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/csv2vcf.py b/csv2vcf.py index 73d65f4..b04adde 100644 --- a/csv2vcf.py +++ b/csv2vcf.py @@ -10,18 +10,38 @@ import csv import json +default_input_file_format = { + 'first_name': None, + 'last_name': None, + 'full_name': None, + 'nickname': None, + 'org': None, + 'tel': None, + 'url': None, + 'bday': None, + 'role': None, + 'email': None, + 'note': None +} + def convert_to_vcard(input_file, single_output, input_file_format): - FN = input_file_format['name']-1 if 'name' in input_file_format else None - NICKNAME = input_file_format['nickname']-1 if 'nickname' in input_file_format else None - ORG = input_file_format['org']-1 if 'org' in input_file_format else None - TEL = input_file_format['tel']-1 if 'tel' in input_file_format else None - URL = input_file_format['url']-1 if 'url' in input_file_format else None - BDAY = input_file_format['bday']-1 if 'bday' in input_file_format else None - ROLE = input_file_format['role']-1 if 'role' in input_file_format else None - EMAIL = input_file_format['email']-1 if 'email' in input_file_format else None - NOTE = input_file_format['note']-1 if 'note' in input_file_format else None + input_file_format = {**default_input_file_format, **input_file_format} + + FIRST_NAME = input_file_format['first_name'] + LAST_NAME = input_file_format['last_name'] + FULL_NAME = input_file_format['full_name'] + + NICKNAME = input_file_format['nickname'] + + ORG = input_file_format['org'] + TEL = input_file_format['tel'] + URL = input_file_format['url'] + BDAY = input_file_format['bday'] + ROLE = input_file_format['role'] + EMAIL = input_file_format['email'] + NOTE = input_file_format['note'] # if single output option is selected if single_output : @@ -31,7 +51,10 @@ def convert_to_vcard(input_file, single_output, input_file_format): i = 0 for row in reader: - FN_VAL = row[FN] if FN is not None else '' + FN_VAL = row[FULL_NAME] if FULL_NAME is not None else '' + FN_VAL = row[FIRST_NAME] + ' ' + \ + row[LAST_NAME] if FN_VAL == '' else FN_VAL + NICKNAME_VAL = row[NICKNAME] if NICKNAME is not None else '' ORG_VAL = row[ORG] if ORG is not None else '' TEL_VAL = row[TEL] if TEL is not None else '' @@ -85,7 +108,10 @@ def convert_to_vcard(input_file, single_output, input_file_format): i = 0 for row in reader: - FN_VAL = row[FN] if FN is not None else '' + FN_VAL = row[FULL_NAME] if FULL_NAME is not None else '' + FN_VAL = row[FIRST_NAME] + ' ' + \ + row[LAST_NAME] if FN_VAL == '' else FN_VAL + NICKNAME_VAL = row[NICKNAME] if NICKNAME is not None else '' ORG_VAL = row[ORG] if ORG is not None else '' TEL_VAL = row[TEL] if TEL is not None else '' From c524a15577ed7f95c659be10204761d3e9fb3513 Mon Sep 17 00:00:00 2001 From: Juan Rodriguez Date: Sat, 15 Apr 2023 09:31:18 +0200 Subject: [PATCH 2/3] fix: reader BOOM char utf-8-sig, DictReader index by key names --- csv2vcf.py | 107 ++++++++++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/csv2vcf.py b/csv2vcf.py index b04adde..ef2b180 100644 --- a/csv2vcf.py +++ b/csv2vcf.py @@ -44,9 +44,9 @@ def convert_to_vcard(input_file, single_output, input_file_format): NOTE = input_file_format['note'] # if single output option is selected - if single_output : - with open( input_file, 'r' ) as source_file: - reader = csv.reader( source_file ) + if single_output: + with open(input_file, 'r', encoding='utf-8-sig') as source_file: + reader = csv.DictReader(source_file) single_vcf = open('csv2vcf/all_contacts.vcf', 'w') i = 0 for row in reader: @@ -80,20 +80,20 @@ def convert_to_vcard(input_file, single_output, input_file_format): print('----------------------') # write the single file - single_vcf.write( 'BEGIN:VCARD' + "\n") - single_vcf.write( 'VERSION:3.0' + "\n") - single_vcf.write( 'N:' + FN_VAL + ';' + "\n") - single_vcf.write( 'FN:' + FN_VAL + "\n") - single_vcf.write( 'NICKNAME:' + NICKNAME_VAL + "\n") - single_vcf.write( 'TEL;HOME;VOICE:' + TEL_VAL + "\n") - single_vcf.write( 'EMAIL:' + EMAIL_VAL + "\n") - single_vcf.write( 'BDAY:' + BDAY_VAL + "\n") - single_vcf.write( 'ORG:' + ORG_VAL + "\n") - single_vcf.write( 'ROLE:' + ROLE_VAL + "\n") - single_vcf.write( 'URL:' + URL_VAL + "\n") - single_vcf.write( 'NOTE:' + NOTE_VAL + "\n") - single_vcf.write( 'END:VCARD' + "\n") - single_vcf.write( "\n") + single_vcf.write('BEGIN:VCARD' + "\n") + single_vcf.write('VERSION:3.0' + "\n") + single_vcf.write('N:' + FN_VAL + ';' + "\n") + single_vcf.write('FN:' + FN_VAL + "\n") + single_vcf.write('NICKNAME:' + NICKNAME_VAL + "\n") + single_vcf.write('TEL;HOME;VOICE:' + TEL_VAL + "\n") + single_vcf.write('EMAIL:' + EMAIL_VAL + "\n") + single_vcf.write('BDAY:' + BDAY_VAL + "\n") + single_vcf.write('ORG:' + ORG_VAL + "\n") + single_vcf.write('ROLE:' + ROLE_VAL + "\n") + single_vcf.write('URL:' + URL_VAL + "\n") + single_vcf.write('NOTE:' + NOTE_VAL + "\n") + single_vcf.write('END:VCARD' + "\n") + single_vcf.write("\n") i += 1 @@ -102,9 +102,9 @@ def convert_to_vcard(input_file, single_output, input_file_format): print('----------------------') # default ( multi-file output ) - else : - with open( input_file, 'r' ) as source_file: - reader = csv.reader( source_file ) + else: + with open(input_file, 'r', encoding='utf-8-sig') as source_file: + reader = csv.DictReader(source_file) i = 0 for row in reader: @@ -137,20 +137,21 @@ def convert_to_vcard(input_file, single_output, input_file_format): print('----------------------') # write each entry - each_vcf = open('csv2vcf/' + FN_VAL + '_' + TEL_VAL + ".vcf", 'w') - each_vcf.write( 'BEGIN:VCARD' + "\n") - each_vcf.write( 'VERSION:3.0' + "\n") - each_vcf.write( 'N:' + FN_VAL + ';' + "\n") - each_vcf.write( 'FN:' + FN_VAL + "\n") - each_vcf.write( 'NICKNAME:' + NICKNAME_VAL + "\n") - each_vcf.write( 'TEL;HOME;VOICE:' + TEL_VAL + "\n") - each_vcf.write( 'EMAIL:' + EMAIL_VAL + "\n") - each_vcf.write( 'BDAY:' + BDAY_VAL + "\n") - each_vcf.write( 'ORG:' + ORG_VAL + "\n") - each_vcf.write( 'ROLE:' + ROLE_VAL + "\n") - each_vcf.write( 'URL:' + URL_VAL + "\n") - each_vcf.write( 'NOTE:' + NOTE_VAL + "\n") - each_vcf.write( 'END:VCARD' + "\n") + each_vcf = open('csv2vcf/' + FN_VAL + + '_' + TEL_VAL + ".vcf", 'w') + each_vcf.write('BEGIN:VCARD' + "\n") + each_vcf.write('VERSION:3.0' + "\n") + each_vcf.write('N:' + FN_VAL + ';' + "\n") + each_vcf.write('FN:' + FN_VAL + "\n") + each_vcf.write('NICKNAME:' + NICKNAME_VAL + "\n") + each_vcf.write('TEL;HOME;VOICE:' + TEL_VAL + "\n") + each_vcf.write('EMAIL:' + EMAIL_VAL + "\n") + each_vcf.write('BDAY:' + BDAY_VAL + "\n") + each_vcf.write('ORG:' + ORG_VAL + "\n") + each_vcf.write('ROLE:' + ROLE_VAL + "\n") + each_vcf.write('URL:' + URL_VAL + "\n") + each_vcf.write('NOTE:' + NOTE_VAL + "\n") + each_vcf.write('END:VCARD' + "\n") each_vcf.write("\n") each_vcf.close() @@ -163,44 +164,50 @@ def convert_to_vcard(input_file, single_output, input_file_format): def main(args): args_len = len(args) - if args_len < 3 or args_len > 4 : - print ( "Usage:") - print ( args[0] + " filename") + if args_len < 3 or args_len > 4: + print("Usage:") + print(args[0] + " filename") sys.exit() - if args_len == 3 : + if args_len == 3: input_file = args[1] - - try : + + try: input_file_format = json.loads(args[2]) - except Exception as e : + except Exception: print('\033[91m'+"ERROR : json could not be parsed"+'\033[0m') sys.exit() single_output = 0 - elif args_len == 4 : + elif args_len == 4: input_file = args[1] - if args[2] == '-s' or args[2] == '--single' : + if args[2] == '-s' or args[2] == '--single': single_output = 1 - else : - print('\033[91m'+"ERROR : invalid argument `" + args[2] + "`"+'\033[0m') + else: + print('\033[91m'+"ERROR : invalid argument `" + + args[2] + "`"+'\033[0m') sys.exit() - try : + try: input_file_format = json.loads(args[3]) - except Exception as e : + except Exception: print('\033[91m'+"ERROR : json could not be parsed"+'\033[0m') sys.exit() - if not os.path.exists(input_file) : - print('\033[91m'+"ERROR : file `" + input_file + "` not found"+'\033[0m') + if not os.path.exists(input_file): + print('\033[91m'+"ERROR : file `" + + input_file + "` not found"+'\033[0m') sys.exit() - if not os.path.exists('csv2vcf') : + if not os.path.exists('csv2vcf'): os.makedirs('csv2vcf') convert_to_vcard(input_file, single_output, input_file_format) + print('\033[92m'+"DONE"+'\033[0m') + print("Output files are in `csv2vcf` folder") + + if __name__ == '__main__': main(sys.argv) From a93e164479ab8660c960bbf483bd62b7ca9dcd7c Mon Sep 17 00:00:00 2001 From: Juan Rodriguez Date: Sat, 15 Apr 2023 09:39:55 +0200 Subject: [PATCH 3/3] chore: update README.md --- README.md | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f1ba810..544c0c3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # csv2vcf csv2vcf is a small command line tool to convert CSV files to VCard (.vcf) files. -## Usage : +## Usage Go to terminal or command prompt and type : @@ -9,47 +9,56 @@ Go to terminal or command prompt and type : python csv2vcf.py CSV_FILE_NAME [ -s | --single ] INPUT_FILE_FORMAT ``` -Where : +Where - `CSV_FILE_NAME` is the full name of the CSV file you want to convert - `INPUT_FILE_FORMAT` is a JSON formatted string which tells **csv2vcf** how to parse your input file - `-s` or `--single` : use this argument if you want your output in a single file. Optional parameter. By default, the program will create separate Vcard files for each entry +### JSON Format +The JSON string can have the following keys ([vCard property types](https://en.wikipedia.org/wiki/VCard)) : -###### JSON Format : +| key titles | +|------------| +| first_name | +| last_name | +| full_name | +| nickname | +| tel | +| email | +| org | +| url | +| bday | +| role | -The JSON string can have the following keys : +Format is `{KEY_1:KEY_1_TITLE, KEY_2:KEY_2_TITLE, ...}` -`name`, `nickname`, `org`, `tel`, `url`, `bday`, `role`, and `email`, where each property is in accordance with [vCard property types](https://en.wikipedia.org/wiki/VCard) -Format is `{KEY_1:KEY_1_COLUMN_NO, KEY_2:KEY_2_COLUMN_NO, ...}` - - -###### Example : +###### Example Suppose you have a CSV file `contacts.csv` with the following content : ``` -+-----------+-------------+ -| NAME | MOBILE | -+-----------+-------------+ -| Mrid | 1111111111 | -| Arnav | 2222222222 | -| Sunil | 3333333333 | -| . | . | -| . | . | -| . | . | -+-----------+-------------+ ++-----------+--------------+ +| NAME | MOBILE PHONE | ++-----------+--------------+ +| Mrid | 1111111111 | +| Arnav | 2222222222 | +| Sunil | 3333333333 | +| . | . | +| . | . | +| . | . | ++-----------+--------------+ ``` -To convert this file to vCard, you will have to write : +To convert this file to vCard, you will have to write: -`python csv2vcf.py contacts.csv '{"name":1, "tel":2}'` +`python csv2vcf.py contacts.csv '{"full_name": "NAME", "tel": "MOBILE PHONE"}'` if you want separate vCards for each person, or -`python csv2vcf.py contacts.csv -s '{"name":1, "tel":2}'` +`python csv2vcf.py contacts.csv -s '{"full_name": "NAME", "tel": "MOBILE PHONE"}'` if you want to generate a single vCard file