2 """Quick, dirty script that will convert a csv file to yaml, spawn an editor
3 for you to fiddle with it, then convert back to csv and replace the original
6 Run me as: $0 some_file.csv
8 The editor used is $EDITOR, of course.
10 This script is not guaranteed to be even remotely reliable, so consider only
11 using it on files in source control.
24 sys.stderr.write("Please install PyYAML.\n")
27 # Try to use ordered dicts, so the YAML keys are in database table order
28 odict = dict # fall back to regular dict
30 from collections import OrderedDict as odict
33 # This is a library for 2.4-2.6
34 from ordereddict import OrderedDict as odict
38 # Tell PyYAML how to dump our ordered dict.
39 # The items() is to avoid the sorting the library does automatically.
40 # Needs to be added to SafeDumper manually, because we use safe_dump below, and
41 # every Representer class has its own independent goddamn dict of these things
42 from yaml.dumper import SafeDumper
45 lambda dumper, data: dumper.represent_dict(data.items()),
50 infilename, = sys.argv[1:]
53 with open(infilename) as infile:
54 reader = csv.reader(infile, lineterminator='\n')
55 column_names = [unicode(column) for column in next(reader)]
60 for col, value in zip(column_names, row):
61 datum[col] = value.decode('utf-8')
66 # Monkeypatch yaml to use > syntax for multiline text; easier to edit
67 from yaml.emitter import Emitter
68 orig_choose_scalar_style = Emitter.choose_scalar_style
69 def new_choose_scalar_style(self):
70 if self.analysis is None:
71 self.analysis = self.analyze_scalar(self.event.value)
72 if self.analysis.multiline or len(self.analysis.scalar) > 80:
74 return orig_choose_scalar_style(self)
75 Emitter.choose_scalar_style = new_choose_scalar_style
78 with tempfile.NamedTemporaryFile(suffix='.yml') as tmp:
79 yaml.safe_dump(data, tmp,
80 default_flow_style=False,
84 del data # reclaim rams!
86 error_line = '' # used on errors
88 args = [os.environ['EDITOR'], tmp.name]
89 if 'vim' in os.environ['EDITOR']:
90 # vim has an arg for jumping to a line:
91 args.append("+{0}".format(error_line))
93 # Run the user's editor and wait for it to close
94 subprocess.Popen(args).wait()
98 new_data = yaml.safe_load(tmp)
100 except yaml.YAMLError as e:
101 if hasattr(e, 'problem_mark'):
102 error_line = e.problem_mark.line + 1
107 print "Oh my god what have you done:"
111 print "Press Enter to try again, or I guess ctrl-c to bail."
114 with open(infilename, 'wb') as outfile:
115 writer = csv.writer(outfile, lineterminator='\n')
116 writer.writerow([ column.encode('utf8') for column in column_names ])
118 for datum in new_data:
120 datum[column].encode('utf8') for column in column_names