Puzzles
There are a number of things that puzzle me about the intention of this code. The most weird thing, I think, is if idLine in new_line
and if system in new_line
. That means that you are performing a join of the second column in users.csv
to any column in vms.csv
, and a join of the first column in OS.csv
to any column in vms.csv
. Typically, you would want to perform each join with one specific column in vms.csv
. If that's not a bug, then there needs to be a comment explaining your intention.
I would love to find out what the columns in these files represent. The code could be rewritten more clearly if I knew more than the column numbers, but I can't help you with that given the current partial information in the question.
Naming
Notice the inconsistencies:
- File handles
input_fileVms
, output_merge
, input_fileUsers
, OSFile
- CSV reader/writers
dataVms
, writerMerge
, dataUsers
, OS
File handling
fileUsers
is the only file handle that you properly close. Failing to OSFile
is particularly bad, because you open it once per line in vms.csv
.
As others have pointed out, opening and reading the entire users.csv
and OS.csv
for each line in vms.csv
will lead to poor performance. You should read users.csv
and OS.csv
into memory just once.
The best way to take care of these problems is with a single with
block:
if site in ['eg', 'fm']:
with open('users.csv', 'rb') as user_input_file, \
open('OS.csv', 'rb') as os_input_file, \
open('vms.csv', 'rb') as vm_input_file, \
open('mergedFile%s.csv' % site.upper(), 'wb') as merge_output_file:
merge(merge_output_file, vm_input_file, os_input_file, user_input_file)
(As a general rule, you always want to call open()
in the context of a with
block.)
Miscellaneous
Take advantage of generators and list comprehensions to reduce excessive indentation.
In these lines…
if len(user) < 5:
writerMerge.writerow((str(new_line[2] + ',' + user[2] + "," + "Missing"+ ',' +OS[1])).split(','))
else:
writerMerge.writerow((str(new_line[2] + ',' + user[2] + "," +user[4]+ ',' +OS[1])).split(','))
… I don't understand why you need to call str(…)
, or why you concatenate and then split the results again. Also, I suggest changing the condition to len(user) <= 4
instead, so that you don't have both 4 and 5 as special numbers.
Suggested solution
To go with the with
block above…
def merge(merge_output_file, vm_input_file, os_input_file, user_input_file):
user_reader = csv.reader(user_input_file)
user_list = [
user for user in (
strip(row) for i, row in enumerate(user_reader)
if i >= 4 # Skip first 4 lines
) if len(user) >= 4 # Drop short lines
]
os_reader = csv.reader(os_input_file)
os_list = list(os_reader)
vm_reader = csv.reader(vm_input_file)
merge_writer = csv.writer(merge_output_file, quoting=csv.QUOTE_ALL)
for vm_row in vm_reader:
vm_row = strip(vm_row)
for user in (user for user in user_list if str(user[1]) in vm_row):
for os in (os for os in os_list if os[0] in vm_row):
merge_writer.writerow([
vm_row[2],
user[2],
user[4] if len(user) > 4 else 'Missing',
os[1],
])
user = strip(user)
? Isstrip
one of your custom functions and this line doing more or lessuser = list(map(str.strip, user))
? \$\endgroup\$