4 from sqlalchemy
.exc
import IntegrityError
5 import sqlalchemy
.types
7 from .db
import connect
, metadata
, tables
as tables_module
10 if len(sys
.argv
) <= 1:
16 # Find the command as a function in this file
17 func
= globals().get(command
, None)
18 if func
and callable(func
) and command
!= 'main':
24 def csvimport(engine_uri
, directory
='.'):
27 from sqlalchemy
.orm
.attributes
import instrumentation_registry
29 # Use autocommit in case rows fail due to foreign key incest
30 session
= connect(engine_uri
, autocommit
=True, autoflush
=False)
34 # SQLAlchemy is retarded and there is no way for me to get a list of ORM
35 # classes besides to inspect the module they all happen to live in for
36 # things that look right.
37 table_base
= tables_module
.TableBase
38 orm_classes
= {} # table object => table class
40 for name
in dir(tables_module
):
41 # dir() returns strings! How /convenient/.
42 thingy
= getattr(tables_module
, name
)
44 if not isinstance(thingy
, type):
47 elif not issubclass(thingy
, table_base
):
48 # Not a declarative table; bail
50 elif thingy
== table_base
:
51 # Declarative table base, so not a real table; bail
54 # thingy is definitely a table class! Hallelujah.
55 orm_classes
[thingy
.__table__
] = thingy
57 # Okay, run through the tables and actually load the data now
58 for table_obj
in metadata
.sorted_tables
:
59 table_class
= orm_classes
[table_obj
]
60 table_name
= table_obj
.name
62 # Print the table name but leave the cursor in a fixed column
63 print table_name
+ '...', ' ' * (40 - len(table_name
)),
67 csvfile
= open("%s/%s.csv" %
(directory
, table_name
), 'rb')
69 # File doesn't exist; don't load anything!
73 reader
= csv
.reader(csvfile
, lineterminator
='\n')
74 column_names
= [unicode(column
) for column
in reader
.next()]
76 # Self-referential tables may contain rows with foreign keys of
77 # other rows in the same table that do not yet exist. We'll keep
78 # a running list of these and try inserting them again after the
85 for column_name
, value
in zip(column_names
, csvs
):
86 column
= table_obj
.c
[column_name
]
87 if column
.nullable
and value
== '':
88 # Empty string in a nullable column really means NULL
90 elif isinstance(column
.type, sqlalchemy
.types
.Boolean
):
91 # Boolean values are stored as string values 0/1, but both
92 # of those evaluate as true; SQLA wants True/False
98 # Otherwise, unflatten from bytes
99 value
= value
.decode('utf-8')
101 setattr(row
, column_name
, value
)
106 except IntegrityError
as e
:
107 failed_rows
.append(row
)
109 # Loop over the failed rows and keep trying to insert them. If a loop
110 # doesn't manage to insert any rows, bail.
111 do_another_loop
= True
112 while failed_rows
and do_another_loop
:
113 do_another_loop
= False
115 for i
, row
in enumerate(failed_rows
):
122 do_another_loop
= True
123 except IntegrityError
as e
:
127 print len(failed_rows
), "rows failed"
131 def csvexport(engine_uri
, directory
='.'):
133 session
= connect(engine_uri
)
135 for table_name
in sorted(metadata
.tables
.keys()):
137 table
= metadata
.tables
[table_name
]
139 writer
= csv
.writer(open("%s/%s.csv" %
(directory
, table_name
), 'wb'),
141 columns
= [col
.name
for col
in table
.columns
]
142 writer
.writerow(columns
)
144 for row
in session
.query(table
).all():
147 # Convert Pythony values to something more universal
148 val
= getattr(row
, col
)
156 val
= unicode(val
).encode('utf-8')
160 writer
.writerow(csvs
)
164 print u
"""pokedex -- a command-line Pokédex interface
166 help Displays this message.
168 These commands are only useful for developers:
169 csvimport {uri} [dir] Import data from a set of CSVs to the database
171 csvexport {uri} [dir] Export data from the database given by the URI
173 Directory defaults to cwd.