Another rearrangement of CSV rows by primary key.
[zzz-pokedex.git] / pokedex / __init__.py
1 # encoding: utf8
2 import sys
3
4 import sqlalchemy.types
5
6 from .db import connect, metadata, tables as tables_module
7
8 def main():
9 if len(sys.argv) <= 1:
10 help()
11
12 command = sys.argv[1]
13 args = sys.argv[2:]
14
15 # Find the command as a function in this file
16 func = globals().get(command, None)
17 if func and callable(func) and command != 'main':
18 func(*args)
19 else:
20 help()
21
22
23 def csvimport(engine_uri, directory='.'):
24 import csv
25
26 from sqlalchemy.orm.attributes import instrumentation_registry
27
28 session = connect(engine_uri)
29
30 metadata.create_all()
31
32 # Oh, mysql-chan.
33 # TODO try to insert data in preorder so we don't need this hack and won't
34 # break similarly on other engines
35 if 'mysql' in engine_uri:
36 session.execute('SET FOREIGN_KEY_CHECKS = 0')
37
38 # SQLAlchemy is retarded and there is no way for me to get a list of ORM
39 # classes besides to inspect the module they all happen to live in for
40 # things that look right.
41 table_base = tables_module.TableBase
42 orm_classes = {}
43
44 for name in dir(tables_module):
45 # dir() returns strings! How /convenient/.
46 thingy = getattr(tables_module, name)
47
48 if not isinstance(thingy, type):
49 # Not a class; bail
50 continue
51 elif not issubclass(thingy, table_base):
52 # Not a declarative table; bail
53 continue
54 elif thingy == table_base:
55 # Declarative table base, so not a real table; bail
56 continue
57
58 # thingy is definitely a table class! Hallelujah.
59 orm_classes[thingy.__table__.name] = thingy
60
61 # Okay, run through the tables and actually load the data now
62 for table_name, table in sorted(orm_classes.items()):
63 # Print the table name but leave the cursor in a fixed column
64 print table_name + '...', ' ' * (40 - len(table_name)),
65
66 try:
67 csvfile = open("%s/%s.csv" % (directory, table_name), 'rb')
68 except IOError:
69 # File doesn't exist; don't load anything!
70 print 'no data!'
71 continue
72
73 reader = csv.reader(csvfile, lineterminator='\n')
74 column_names = [unicode(column) for column in reader.next()]
75
76 for csvs in reader:
77 row = table()
78
79 for column_name, value in zip(column_names, csvs):
80 column = table.__table__.c[column_name]
81 if column.nullable and value == '':
82 # Empty string in a nullable column really means NULL
83 value = None
84 elif isinstance(column.type, sqlalchemy.types.Boolean):
85 # Boolean values are stored as string values 0/1, but both
86 # of those evaluate as true; SQLA wants True/False
87 if value == '0':
88 value = False
89 else:
90 value = True
91 else:
92 # Otherwise, unflatten from bytes
93 value = value.decode('utf-8')
94
95 setattr(row, column_name, value)
96
97 session.add(row)
98
99 session.commit()
100 print 'loaded'
101
102 # Shouldn't matter since this is usually the end of the program and thus
103 # the connection too, but let's change this back just in case
104 if 'mysql' in engine_uri:
105 session.execute('SET FOREIGN_KEY_CHECKS = 1')
106
107
108 def csvexport(engine_uri, directory='.'):
109 import csv
110 session = connect(engine_uri)
111
112 for table_name in sorted(metadata.tables.keys()):
113 print table_name
114 table = metadata.tables[table_name]
115
116 writer = csv.writer(open("%s/%s.csv" % (directory, table_name), 'wb'),
117 lineterminator='\n')
118 columns = [col.name for col in table.columns]
119 writer.writerow(columns)
120
121 for row in session.query(table).all():
122 csvs = []
123 for col in columns:
124 # Convert Pythony values to something more universal
125 val = getattr(row, col)
126 if val == None:
127 val = ''
128 elif val == True:
129 val = '1'
130 elif val == False:
131 val = '0'
132 else:
133 val = unicode(val).encode('utf-8')
134
135 csvs.append(val)
136
137 writer.writerow(csvs)
138
139
140 def help():
141 print u"""pokedex -- a command-line Pokédex interface
142
143 help Displays this message.
144
145 These commands are only useful for developers:
146 csvimport {uri} [dir] Import data from a set of CSVs to the database
147 given by the URI.
148 csvexport {uri} [dir] Export data from the database given by the URI
149 to a set of CSVs.
150 Directory defaults to cwd.
151 """
152
153 sys.exit(0)