Merge remote-tracking branch 'origin/encounters-i18n'

Conflicts:
	pokedex/db/__init__.py
This commit is contained in:
Eevee 2011-04-05 22:32:51 -07:00
commit 905f5b3d13
27 changed files with 12048 additions and 437 deletions

View file

@ -1,287 +0,0 @@
# encoding: utf8
from optparse import OptionParser
import os
import sys
# XXX importing pokedex.whatever should not import all these
import pokedex.db
import pokedex.db.load
import pokedex.db.tables
import pokedex.lookup
from pokedex import defaults
def main():
if len(sys.argv) <= 1:
command_help()
command = sys.argv[1]
args = sys.argv[2:]
# XXX there must be a better way to get Unicode argv
# XXX this doesn't work on Windows durp
enc = sys.stdin.encoding or 'utf8'
args = [_.decode(enc) for _ in args]
# Find the command as a function in this file
func = globals().get("command_%s" % command, None)
if func:
func(*args)
else:
command_help()
def get_parser(verbose=True):
"""Returns an OptionParser prepopulated with the global options.
`verbose` is whether or not the options should be verbose by default.
"""
parser = OptionParser()
parser.add_option('-e', '--engine', dest='engine_uri', default=None)
parser.add_option('-i', '--index', dest='index_dir', default=None)
parser.add_option('-q', '--quiet', dest='verbose', default=verbose, action='store_false')
parser.add_option('-v', '--verbose', dest='verbose', default=verbose, action='store_true')
return parser
def get_session(options):
"""Given a parsed options object, connects to the database and returns a
session.
"""
engine_uri = options.engine_uri
got_from = 'command line'
if engine_uri is None:
engine_uri, got_from = defaults.get_default_db_uri_with_origin()
session = pokedex.db.connect(engine_uri)
if options.verbose:
print "Connected to database %(engine)s (from %(got_from)s)" \
% dict(engine=session.bind.url, got_from=got_from)
return session
def get_lookup(options, session=None, recreate=False):
"""Given a parsed options object, opens the whoosh index and returns a
PokedexLookup object.
"""
if recreate and not session:
raise ValueError("get_lookup() needs an explicit session to regen the index")
index_dir = options.index_dir
got_from = 'command line'
if index_dir is None:
index_dir, got_from = defaults.get_default_index_dir_with_origin()
if options.verbose:
print "Opened lookup index %(index_dir)s (from %(got_from)s)" \
% dict(index_dir=index_dir, got_from=got_from)
lookup = pokedex.lookup.PokedexLookup(index_dir, session=session)
if recreate:
lookup.rebuild_index()
return lookup
def get_csv_directory(options):
"""Prints and returns the csv directory we're about to use."""
if not options.verbose:
return
csvdir = options.directory
got_from = 'command line'
if csvdir is None:
csvdir, got_from = defaults.get_default_csv_dir_with_origin()
print "Using CSV directory %(csvdir)s (from %(got_from)s)" \
% dict(csvdir=csvdir, got_from=got_from)
return csvdir
### Plumbing commands
def command_dump(*args):
parser = get_parser(verbose=True)
parser.add_option('-d', '--directory', dest='directory', default=None)
options, tables = parser.parse_args(list(args))
session = get_session(options)
get_csv_directory(options)
pokedex.db.load.dump(session, directory=options.directory,
tables=tables,
verbose=options.verbose)
def command_load(*args):
parser = get_parser(verbose=True)
parser.add_option('-d', '--directory', dest='directory', default=None)
parser.add_option('-D', '--drop-tables', dest='drop_tables', default=False, action='store_true')
parser.add_option('-S', '--safe', dest='safe', default=False, action='store_true',
help="Do not use backend-specific optimalizations.")
options, tables = parser.parse_args(list(args))
if not options.engine_uri:
print "WARNING: You're reloading the default database, but not the lookup index. They"
print " might get out of sync, and pokedex commands may not work correctly!"
print "To fix this, run `pokedex reindex` when this command finishes. Or, just use"
print "`pokedex setup` to do both at once."
print
session = get_session(options)
get_csv_directory(options)
pokedex.db.load.load(session, directory=options.directory,
drop_tables=options.drop_tables,
tables=tables,
verbose=options.verbose,
safe=options.safe)
def command_reindex(*args):
parser = get_parser(verbose=True)
options, _ = parser.parse_args(list(args))
session = get_session(options)
lookup = get_lookup(options, session=session, recreate=True)
print "Recreated lookup index."
def command_setup(*args):
parser = get_parser(verbose=False)
options, _ = parser.parse_args(list(args))
options.directory = None
session = get_session(options)
get_csv_directory(options)
pokedex.db.load.load(session, directory=None, drop_tables=True,
verbose=options.verbose,
safe=False)
lookup = get_lookup(options, session=session, recreate=True)
print "Recreated lookup index."
def command_status(*args):
parser = get_parser(verbose=True)
options, _ = parser.parse_args(list(args))
options.verbose = True
options.directory = None
# Database, and a lame check for whether it's been inited at least once
session = get_session(options)
print " - OK! Connected successfully."
if pokedex.db.tables.Pokemon.__table__.exists(session.bind):
print " - OK! Database seems to contain some data."
else:
print " - WARNING: Database appears to be empty."
# CSV; simple checks that the dir exists
csvdir = get_csv_directory(options)
if not os.path.exists(csvdir):
print " - ERROR: No such directory!"
elif not os.path.isdir(csvdir):
print " - ERROR: Not a directory!"
else:
print " - OK! Directory exists."
if os.access(csvdir, os.R_OK):
print " - OK! Can read from directory."
else:
print " - ERROR: Can't read from directory!"
if os.access(csvdir, os.W_OK):
print " - OK! Can write to directory."
else:
print " - WARNING: Can't write to directory! " \
"`dump` will not work. You may need to sudo."
# Index; the PokedexLookup constructor covers most tests and will
# cheerfully bomb if they fail
lookup = get_lookup(options, recreate=False)
print " - OK! Opened successfully."
### User-facing commands
def command_lookup(*args):
parser = get_parser(verbose=False)
options, words = parser.parse_args(list(args))
name = u' '.join(words)
session = get_session(options)
lookup = get_lookup(options, session=session, recreate=False)
results = lookup.lookup(name)
if not results:
print "No matches."
elif results[0].exact:
print "Matched:"
else:
print "Fuzzy-matched:"
for result in results:
if hasattr(result.object, 'full_name'):
name = result.object.full_name
else:
name = result.object.name
print "%s: %s" % (result.object.__tablename__, name),
if result.language:
print "(%s in %s)" % (result.name, result.language)
else:
print
def command_help():
print u"""pokedex -- a command-line Pokédex interface
usage: pokedex {command} [options...]
Run `pokedex setup` first, or nothing will work!
See http://bugs.veekun.com/projects/pokedex/wiki/CLI for more documentation.
Commands:
help Displays this message.
lookup [thing] Look up something in the Pokédex.
System commands:
load Load Pokédex data into a database from CSV files.
dump Dump Pokédex data from a database into CSV files.
reindex Rebuilds the lookup index from the database.
setup Combines load and reindex.
status No effect, but prints which engine, index, and csv
directory would be used for other commands.
Global options:
-e|--engine=URI By default, all commands try to use a SQLite database
in the pokedex install directory. Use this option (or
a POKEDEX_DB_ENGINE environment variable) to specify an
alternate database.
-i|--index=DIR By default, all commands try to put the lookup index in
the pokedex install directory. Use this option (or a
POKEDEX_INDEX_DIR environment variable) to specify an
alternate loction.
-q|--quiet Don't print system output. This is the default for
non-system commands and setup.
-v|--verbose Print system output. This is the default for system
commands, except setup.
System options:
-d|--directory=DIR By default, load and dump will use the CSV files in the
pokedex install directory. Use this option to specify
a different directory.
-D|--drop-tables With load, drop all tables before loading data.
Additionally, load and dump accept a list of table names (possibly with
wildcards) and/or csv fileames as an argument list.
""".encode(sys.getdefaultencoding(), 'replace')
sys.exit(0)

View file

@ -1,16 +1,16 @@
id,identifier
1,monster
2,water-1
2,water1
3,bug
4,flying
5,ground
6,fairy
7,plant
8,humanshape
9,water-3
9,water3
10,mineral
11,indeterminate
12,water-2
12,water2
13,ditto
14,dragon
15,no-eggs

1 id identifier
2 1 monster
3 2 water-1 water1
4 3 bug
5 4 flying
6 5 ground
7 6 fairy
8 7 plant
9 8 humanshape
10 9 water-3 water3
11 10 mineral
12 11 indeterminate
13 12 water-2 water2
14 13 ditto
15 14 dragon
16 15 no-eggs

View file

@ -1,17 +1,17 @@
id,encounter_condition_id,identifier,is_default
1,1,during-a-swarm,0
2,1,not-during-a-swarm,1
3,2,in-the-morning,0
4,2,during-the-day,1
5,2,at-night,0
6,3,using-pokeradar,0
7,3,not-using-pokeradar,1
8,4,no-game-in-slot-2,1
9,4,ruby-in-slot-2,0
10,4,sapphire-in-slot-2,0
11,4,emerald-in-slot-2,0
12,4,firered-in-slot-2,0
13,4,leafgreen-in-slot-2,0
1,1,swarm-yes,0
2,1,swarm-no,1
3,2,time-morning,0
4,2,time-day,1
5,2,time-night,0
6,3,radar-on,0
7,3,radar-off,1
8,4,slot2-none,1
9,4,slot2-ruby,0
10,4,slot2-sapphire,0
11,4,slot2-emerald,0
12,4,slot2-firered,0
13,4,slot2-leafgreen,0
14,5,radio-off,1
15,5,hoenn-radio,0
16,5,sinnoh-radio,0
15,5,radio-hoenn,0
16,5,radio-sinnoh,0

1 id encounter_condition_id identifier is_default
2 1 1 during-a-swarm swarm-yes 0
3 2 1 not-during-a-swarm swarm-no 1
4 3 2 in-the-morning time-morning 0
5 4 2 during-the-day time-day 1
6 5 2 at-night time-night 0
7 6 3 using-pokeradar radar-on 0
8 7 3 not-using-pokeradar radar-off 1
9 8 4 no-game-in-slot-2 slot2-none 1
10 9 4 ruby-in-slot-2 slot2-ruby 0
11 10 4 sapphire-in-slot-2 slot2-sapphire 0
12 11 4 emerald-in-slot-2 slot2-emerald 0
13 12 4 firered-in-slot-2 slot2-firered 0
14 13 4 leafgreen-in-slot-2 slot2-leafgreen 0
15 14 5 radio-off 1
16 15 5 hoenn-radio radio-hoenn 0
17 16 5 sinnoh-radio radio-sinnoh 0

View file

@ -1,6 +1,6 @@
id,identifier
1,swarm
2,time-of-day
3,pokeradar
4,gen-3-game-in-slot-2
2,time
3,radar
4,slot2
5,radio

1 id identifier
2 1 swarm
3 2 time-of-day time
4 3 pokeradar radar
5 4 gen-3-game-in-slot-2 slot2
6 5 radio

View file

@ -1,4 +1,4 @@
encounter_terrain_id,local_language_id,name
encounter_method_id,local_language_id,name
1,9,Walking in tall grass or a cave
2,9,Fishing with an Old Rod
3,9,Fishing with a Good Rod
1 encounter_terrain_id encounter_method_id local_language_id name
2 1 1 9 Walking in tall grass or a cave
3 2 2 9 Fishing with an Old Rod
4 3 3 9 Fishing with a Good Rod

View file

@ -0,0 +1,8 @@
id,identifier
1,walk
2,old-rod
3,good-rod
4,super-rod
5,surf
6,rock-smash
7,headbutt
1 id identifier
2 1 walk
3 2 old-rod
4 3 good-rod
5 4 super-rod
6 5 surf
7 6 rock-smash
8 7 headbutt

View file

@ -1,4 +1,4 @@
id,version_group_id,encounter_terrain_id,slot,rarity
id,version_group_id,encounter_method_id,slot,rarity
1,8,1,1,20
2,8,1,2,20
3,8,1,3,10
@ -153,3 +153,99 @@ id,version_group_id,encounter_terrain_id,slot,rarity
152,9,5,3,5
153,9,5,4,4
154,9,5,5,1
155,5,3,1,60
156,5,3,2,20
157,5,3,3,20
158,5,2,1,70
159,5,2,2,30
160,5,4,1,40
161,5,4,2,40
162,5,4,3,15
163,5,4,4,4
164,5,4,5,1
165,5,5,1,60
166,5,5,2,30
167,5,5,3,5
168,5,5,4,4
169,5,5,5,1
170,5,1,1,20
171,5,1,2,20
172,5,1,3,10
173,5,1,4,10
174,5,1,5,10
175,5,1,6,10
176,5,1,7,5
177,5,1,8,5
178,5,1,9,4
179,5,1,10,4
180,5,1,11,1
181,5,1,12,1
182,5,6,1,60
183,5,6,2,30
184,5,6,3,5
185,5,6,4,4
186,5,6,5,1
187,6,1,1,20
188,6,1,2,20
189,6,1,3,10
190,6,1,4,10
191,6,1,5,10
192,6,1,6,10
193,6,1,7,5
194,6,1,8,5
195,6,1,9,4
196,6,1,10,4
197,6,1,11,1
198,6,1,12,1
199,6,3,1,60
200,6,3,2,20
201,6,3,3,20
202,6,2,1,70
203,6,2,2,30
204,6,4,1,40
205,6,4,2,40
206,6,4,3,15
207,6,4,4,4
208,6,4,5,1
209,6,5,1,60
210,6,5,2,30
211,6,5,3,5
212,6,5,4,4
213,6,5,5,1
214,6,6,1,60
215,6,6,2,30
216,6,6,3,5
217,6,6,4,4
218,6,6,5,1
219,7,1,1,20
220,7,1,2,20
221,7,1,3,10
222,7,1,4,10
223,7,1,5,10
224,7,1,6,10
225,7,1,7,5
226,7,1,8,5
227,7,1,9,4
228,7,1,10,4
229,7,1,11,1
230,7,1,12,1
231,7,3,1,60
232,7,3,2,20
233,7,3,3,20
234,7,2,1,70
235,7,2,2,30
236,7,4,1,40
237,7,4,2,40
238,7,4,3,15
239,7,4,4,4
240,7,4,5,1
241,7,5,1,60
242,7,5,2,30
243,7,5,3,5
244,7,5,4,4
245,7,5,5,1
246,7,6,1,60
247,7,6,2,30
248,7,6,3,5
249,7,6,4,4
250,7,6,5,1

1 id version_group_id encounter_terrain_id encounter_method_id slot rarity
2 1 8 1 1 20
3 2 8 1 2 20
4 3 8 1 3 10
153 152 9 5 3 5
154 153 9 5 4 4
155 154 9 5 5 1
156 155 5 3 1 60
157 156 5 3 2 20
158 157 5 3 3 20
159 158 5 2 1 70
160 159 5 2 2 30
161 160 5 4 1 40
162 161 5 4 2 40
163 162 5 4 3 15
164 163 5 4 4 4
165 164 5 4 5 1
166 165 5 5 1 60
167 166 5 5 2 30
168 167 5 5 3 5
169 168 5 5 4 4
170 169 5 5 5 1
171 170 5 1 1 20
172 171 5 1 2 20
173 172 5 1 3 10
174 173 5 1 4 10
175 174 5 1 5 10
176 175 5 1 6 10
177 176 5 1 7 5
178 177 5 1 8 5
179 178 5 1 9 4
180 179 5 1 10 4
181 180 5 1 11 1
182 181 5 1 12 1
183 182 5 6 1 60
184 183 5 6 2 30
185 184 5 6 3 5
186 185 5 6 4 4
187 186 5 6 5 1
188 187 6 1 1 20
189 188 6 1 2 20
190 189 6 1 3 10
191 190 6 1 4 10
192 191 6 1 5 10
193 192 6 1 6 10
194 193 6 1 7 5
195 194 6 1 8 5
196 195 6 1 9 4
197 196 6 1 10 4
198 197 6 1 11 1
199 198 6 1 12 1
200 199 6 3 1 60
201 200 6 3 2 20
202 201 6 3 3 20
203 202 6 2 1 70
204 203 6 2 2 30
205 204 6 4 1 40
206 205 6 4 2 40
207 206 6 4 3 15
208 207 6 4 4 4
209 208 6 4 5 1
210 209 6 5 1 60
211 210 6 5 2 30
212 211 6 5 3 5
213 212 6 5 4 4
214 213 6 5 5 1
215 214 6 6 1 60
216 215 6 6 2 30
217 216 6 6 3 5
218 217 6 6 4 4
219 218 6 6 5 1
220 219 7 1 1 20
221 220 7 1 2 20
222 221 7 1 3 10
223 222 7 1 4 10
224 223 7 1 5 10
225 224 7 1 6 10
226 225 7 1 7 5
227 226 7 1 8 5
228 227 7 1 9 4
229 228 7 1 10 4
230 229 7 1 11 1
231 230 7 1 12 1
232 231 7 3 1 60
233 232 7 3 2 20
234 233 7 3 3 20
235 234 7 2 1 70
236 235 7 2 2 30
237 236 7 4 1 40
238 237 7 4 2 40
239 238 7 4 3 15
240 239 7 4 4 4
241 240 7 4 5 1
242 241 7 5 1 60
243 242 7 5 2 30
244 243 7 5 3 5
245 244 7 5 4 4
246 245 7 5 5 1
247 246 7 6 1 60
248 247 7 6 2 30
249 248 7 6 3 5
250 249 7 6 4 4
251 250 7 6 5 1

View file

@ -1,8 +0,0 @@
id,identifier
1,walking-in-tall-grass-or-a-cave
2,fishing-with-an-old-rod
3,fishing-with-a-good-rod
4,fishing-with-a-super-rod
5,surfing
6,smashing-rocks
7,headbutting-trees
1 id identifier
2 1 walking-in-tall-grass-or-a-cave
3 2 fishing-with-an-old-rod
4 3 fishing-with-a-good-rod
5 4 fishing-with-a-super-rod
6 5 surfing
7 6 smashing-rocks
8 7 headbutting-trees

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -304,3 +304,229 @@ location_area_id,local_language_id,name
347,9,"Area 2, north"
348,9,"Area 3, west"
349,9,S.S. Anne dock
350,9,
351,9,
352,9,
353,9,
354,9,
355,9,
356,9,
357,9,back
358,9,B1F
359,9,back/small room
360,9,
361,9,1F
362,9,B1F
363,9,B2F
364,9,1F/small Room
365,9,
366,9,
367,9,
368,9,1F
369,9,2F
370,9,3F
371,9,4F
372,9,5F
373,9,6F
374,9,outside
375,9,summit
376,9,
377,9,entrance
378,9,1F
379,9,B1F
380,9,B2F
381,9,B3F
382,9,1F
383,9,B1F
384,9,B2F
385,9,
386,9,B1F
387,9,Entrance
388,9,
389,9,
390,9,1F
391,9,3F
392,9,5F
393,9,
394,9,
395,9,
396,9,
397,9,
398,9,
399,9,
400,9,
401,9,
402,9,
403,9,
404,9,
405,9,
406,9,
407,9,
408,9,
409,9,
410,9,
411,9,
412,9,
413,9,
414,9,
415,9,
416,9,
417,9,underwater
418,9,
419,9,
420,9,underwater
421,9,
422,9,
423,9,
424,9,
425,9,
426,9,
427,9,
428,9,
429,9,NW/mach bike area
430,9,NE/acro bike area
431,9,SW
432,9,SE
433,9,
434,9,
435,9,expansion south
436,9,expansion north
437,9,
438,9,
439,9,
440,9,
441,9,a
442,9,b
443,9,c
444,9,d
445,9,e
446,9,f
447,9,g
448,9,h
449,9,i
450,9,
451,9,
452,9,
453,9,
454,9,
455,9,
456,9,
457,9,
458,9,1F
459,9,B1F
460,9,B2F
461,9,
462,9,
463,9,1F
464,9,2F
465,9,3F
466,9,
467,9,B1F
468,9,center
469,9,"Area 1, east"
470,9,"Area 2, north"
471,9,"Area 3, west"
472,9,1F
473,9,2F
474,9,B1F
475,9,1F
476,9,B1F
477,9,1F
478,9,B1F
479,9,B2F
480,9,B3F
481,9,B4F
482,9,3F
483,9,4F
484,9,5F
485,9,6F
486,9,7F
487,9,
488,9,
489,9,cave
490,9,inside
491,9,"1F, cave behind team rocket"
492,9,B1F
493,9,B2F
494,9,B3F
495,9,
496,9,entrance
497,9,1F
498,9,B1F
499,9,waterfall
500,9,
501,9,room 1
502,9,room 2
503,9,room 3
504,9,room 4
505,9,room 5
506,9,room 6
507,9,room 7
508,9,room 8
509,9,room 9
510,9,room 10
511,9,item rooms
512,9,
513,9,
514,9,
515,9,
516,9,
517,9,
518,9,
519,9,
520,9,
521,9,
522,9,
523,9,
524,9,
525,9,
526,9,
527,9,
528,9,
529,9,
530,9,
531,9,
532,9,
533,9,
534,9,
535,9,
536,9,
537,9,
538,9,
539,9,
540,9,
541,9,
542,9,
543,9,
544,9,
545,9,
546,9,
547,9,
548,9,
549,9,
550,9,
551,9,
552,9,
553,9,
554,9,
555,9,
556,9,
557,9,
558,9,
559,9,
560,9,
561,9,
562,9,
563,9,
564,9,a
565,9,b
566,9,c
567,9,d
568,9,e
569,9,f
570,9,g
571,9,h
572,9,i
573,9,1F
574,9,2F
575,9,3F

1 location_area_id local_language_id name
304 347 9 Area 2, north
305 348 9 Area 3, west
306 349 9 S.S. Anne dock
307 350 9
308 351 9
309 352 9
310 353 9
311 354 9
312 355 9
313 356 9
314 357 9 back
315 358 9 B1F
316 359 9 back/small room
317 360 9
318 361 9 1F
319 362 9 B1F
320 363 9 B2F
321 364 9 1F/small Room
322 365 9
323 366 9
324 367 9
325 368 9 1F
326 369 9 2F
327 370 9 3F
328 371 9 4F
329 372 9 5F
330 373 9 6F
331 374 9 outside
332 375 9 summit
333 376 9
334 377 9 entrance
335 378 9 1F
336 379 9 B1F
337 380 9 B2F
338 381 9 B3F
339 382 9 1F
340 383 9 B1F
341 384 9 B2F
342 385 9
343 386 9 B1F
344 387 9 Entrance
345 388 9
346 389 9
347 390 9 1F
348 391 9 3F
349 392 9 5F
350 393 9
351 394 9
352 395 9
353 396 9
354 397 9
355 398 9
356 399 9
357 400 9
358 401 9
359 402 9
360 403 9
361 404 9
362 405 9
363 406 9
364 407 9
365 408 9
366 409 9
367 410 9
368 411 9
369 412 9
370 413 9
371 414 9
372 415 9
373 416 9
374 417 9 underwater
375 418 9
376 419 9
377 420 9 underwater
378 421 9
379 422 9
380 423 9
381 424 9
382 425 9
383 426 9
384 427 9
385 428 9
386 429 9 NW/mach bike area
387 430 9 NE/acro bike area
388 431 9 SW
389 432 9 SE
390 433 9
391 434 9
392 435 9 expansion south
393 436 9 expansion north
394 437 9
395 438 9
396 439 9
397 440 9
398 441 9 a
399 442 9 b
400 443 9 c
401 444 9 d
402 445 9 e
403 446 9 f
404 447 9 g
405 448 9 h
406 449 9 i
407 450 9
408 451 9
409 452 9
410 453 9
411 454 9
412 455 9
413 456 9
414 457 9
415 458 9 1F
416 459 9 B1F
417 460 9 B2F
418 461 9
419 462 9
420 463 9 1F
421 464 9 2F
422 465 9 3F
423 466 9
424 467 9 B1F
425 468 9 center
426 469 9 Area 1, east
427 470 9 Area 2, north
428 471 9 Area 3, west
429 472 9 1F
430 473 9 2F
431 474 9 B1F
432 475 9 1F
433 476 9 B1F
434 477 9 1F
435 478 9 B1F
436 479 9 B2F
437 480 9 B3F
438 481 9 B4F
439 482 9 3F
440 483 9 4F
441 484 9 5F
442 485 9 6F
443 486 9 7F
444 487 9
445 488 9
446 489 9 cave
447 490 9 inside
448 491 9 1F, cave behind team rocket
449 492 9 B1F
450 493 9 B2F
451 494 9 B3F
452 495 9
453 496 9 entrance
454 497 9 1F
455 498 9 B1F
456 499 9 waterfall
457 500 9
458 501 9 room 1
459 502 9 room 2
460 503 9 room 3
461 504 9 room 4
462 505 9 room 5
463 506 9 room 6
464 507 9 room 7
465 508 9 room 8
466 509 9 room 9
467 510 9 room 10
468 511 9 item rooms
469 512 9
470 513 9
471 514 9
472 515 9
473 516 9
474 517 9
475 518 9
476 519 9
477 520 9
478 521 9
479 522 9
480 523 9
481 524 9
482 525 9
483 526 9
484 527 9
485 528 9
486 529 9
487 530 9
488 531 9
489 532 9
490 533 9
491 534 9
492 535 9
493 536 9
494 537 9
495 538 9
496 539 9
497 540 9
498 541 9
499 542 9
500 543 9
501 544 9
502 545 9
503 546 9
504 547 9
505 548 9
506 549 9
507 550 9
508 551 9
509 552 9
510 553 9
511 554 9
512 555 9
513 556 9
514 557 9
515 558 9
516 559 9
517 560 9
518 561 9
519 562 9
520 563 9
521 564 9 a
522 565 9 b
523 566 9 c
524 567 9 d
525 568 9 e
526 569 9 f
527 570 9 g
528 571 9 h
529 572 9 i
530 573 9 1F
531 574 9 2F
532 575 9 3F

View file

@ -304,3 +304,229 @@ id,location_id,game_index,identifier
347,162,0,area-2-north
348,162,0,area-3-west
349,151,0,ss-anne-dock
350,429,0,
351,430,1,
352,431,2,
353,432,3,
354,433,4,
355,434,5,
356,435,6,
357,435,7,back
358,435,8,b1f
359,435,9,backsmall-room
360,436,10,
361,437,11,1f
362,437,12,b1f
363,437,13,b2f
364,437,14,1fsmall-room
365,438,15,
366,439,16,
367,440,17,
368,441,18,1f
369,441,19,2f
370,441,20,3f
371,441,21,4f
372,441,22,5f
373,441,23,6f
374,441,24,outside
375,441,25,summit
376,442,26,
377,443,35,entrance
378,443,36,1f
379,443,37,b1f
380,443,38,b2f
381,443,39,b3f
382,444,40,1f
383,444,41,b1f
384,444,42,b2f
385,445,43,
386,445,47,b1f
387,446,48,entrance
388,446,49,
389,447,50,
390,448,52,1f
391,448,53,3f
392,448,54,5f
393,449,55,
394,450,56,
395,451,57,
396,452,58,
397,453,59,
398,454,60,
399,455,61,
400,456,62,
401,457,63,
402,458,64,
403,459,65,
404,460,66,
405,461,67,
406,462,68,
407,463,69,
408,464,70,
409,465,71,
410,466,72,
411,467,73,
412,468,74,
413,469,75,
414,470,76,
415,471,77,
416,472,78,
417,472,95,underwater
418,473,79,
419,474,80,
420,474,96,underwater
421,475,81,
422,476,82,
423,477,83,
424,478,84,
425,479,85,
426,480,86,
427,481,87,
428,482,88,
429,483,89,nwmach-bike-area
430,483,90,neacro-bike-area
431,483,91,sw
432,483,92,se
433,484,93,
434,485,94,
435,483,97,expansion-south
436,483,98,expansion-north
437,486,99,
438,487,107,
439,488,111,
440,489,112,
441,490,114,a
442,490,115,b
443,490,116,c
444,490,117,d
445,490,118,e
446,490,119,f
447,490,120,g
448,490,121,h
449,490,122,i
450,491,0,
451,492,1,
452,493,2,
453,494,3,
454,495,4,
455,496,5,
456,497,6,
457,155,7,
458,80,8,1f
459,80,9,b1f
460,80,10,b2f
461,498,11,
462,73,12,
463,499,13,1f
464,499,14,2f
465,499,15,3f
466,161,16,
467,161,19,b1f
468,162,20,center
469,162,21,area-1-east
470,162,22,area-2-north
471,162,23,area-3-west
472,147,24,1f
473,147,25,2f
474,147,26,b1f
475,87,27,1f
476,87,28,b1f
477,136,29,1f
478,136,30,b1f
479,136,31,b2f
480,136,32,b3f
481,136,33,b4f
482,160,34,3f
483,160,35,4f
484,160,36,5f
485,160,37,6f
486,160,38,7f
487,158,39,
488,500,40,
489,500,41,cave
490,500,42,inside
491,500,44,1f-cave-behind-team-rocket
492,500,45,b1f
493,500,46,b2f
494,500,47,b3f
495,501,50,
496,502,51,entrance
497,502,52,1f
498,502,53,b1f
499,502,54,waterfall
500,503,55,
501,504,56,room-1
502,504,57,room-2
503,504,58,room-3
504,504,59,room-4
505,504,60,room-5
506,504,61,room-6
507,504,62,room-7
508,504,63,room-8
509,504,64,room-9
510,504,65,room-10
511,504,66,item-rooms
512,505,70,
513,506,71,
514,507,72,
515,508,73,
516,509,74,
517,510,75,
518,511,76,
519,512,77,
520,513,78,
521,514,79,
522,515,80,
523,516,81,
524,517,82,
525,518,83,
526,519,84,
527,520,85,
528,521,86,
529,88,87,
530,99,88,
531,109,89,
532,120,90,
533,130,91,
534,131,92,
535,132,93,
536,133,94,
537,134,95,
538,89,96,
539,90,97,
540,91,98,
541,92,99,
542,93,100,
543,94,101,
544,95,102,
545,96,103,
546,97,104,
547,522,105,
548,523,106,
549,524,107,
550,102,109,
551,157,110,
552,103,111,
553,104,112,
554,86,113,
555,154,114,
556,68,115,
557,525,116,
558,67,117,
559,76,118,
560,71,119,
561,526,120,
562,527,121,
563,528,122,
564,529,123,a
565,529,124,b
566,529,125,c
567,529,126,d
568,529,127,e
569,529,128,f
570,529,129,g
571,529,130,h
572,529,131,i
573,530,13,1f
574,530,14,2f
575,530,15,3f

1 id location_id game_index identifier
304 347 162 0 area-2-north
305 348 162 0 area-3-west
306 349 151 0 ss-anne-dock
307 350 429 0
308 351 430 1
309 352 431 2
310 353 432 3
311 354 433 4
312 355 434 5
313 356 435 6
314 357 435 7 back
315 358 435 8 b1f
316 359 435 9 backsmall-room
317 360 436 10
318 361 437 11 1f
319 362 437 12 b1f
320 363 437 13 b2f
321 364 437 14 1fsmall-room
322 365 438 15
323 366 439 16
324 367 440 17
325 368 441 18 1f
326 369 441 19 2f
327 370 441 20 3f
328 371 441 21 4f
329 372 441 22 5f
330 373 441 23 6f
331 374 441 24 outside
332 375 441 25 summit
333 376 442 26
334 377 443 35 entrance
335 378 443 36 1f
336 379 443 37 b1f
337 380 443 38 b2f
338 381 443 39 b3f
339 382 444 40 1f
340 383 444 41 b1f
341 384 444 42 b2f
342 385 445 43
343 386 445 47 b1f
344 387 446 48 entrance
345 388 446 49
346 389 447 50
347 390 448 52 1f
348 391 448 53 3f
349 392 448 54 5f
350 393 449 55
351 394 450 56
352 395 451 57
353 396 452 58
354 397 453 59
355 398 454 60
356 399 455 61
357 400 456 62
358 401 457 63
359 402 458 64
360 403 459 65
361 404 460 66
362 405 461 67
363 406 462 68
364 407 463 69
365 408 464 70
366 409 465 71
367 410 466 72
368 411 467 73
369 412 468 74
370 413 469 75
371 414 470 76
372 415 471 77
373 416 472 78
374 417 472 95 underwater
375 418 473 79
376 419 474 80
377 420 474 96 underwater
378 421 475 81
379 422 476 82
380 423 477 83
381 424 478 84
382 425 479 85
383 426 480 86
384 427 481 87
385 428 482 88
386 429 483 89 nwmach-bike-area
387 430 483 90 neacro-bike-area
388 431 483 91 sw
389 432 483 92 se
390 433 484 93
391 434 485 94
392 435 483 97 expansion-south
393 436 483 98 expansion-north
394 437 486 99
395 438 487 107
396 439 488 111
397 440 489 112
398 441 490 114 a
399 442 490 115 b
400 443 490 116 c
401 444 490 117 d
402 445 490 118 e
403 446 490 119 f
404 447 490 120 g
405 448 490 121 h
406 449 490 122 i
407 450 491 0
408 451 492 1
409 452 493 2
410 453 494 3
411 454 495 4
412 455 496 5
413 456 497 6
414 457 155 7
415 458 80 8 1f
416 459 80 9 b1f
417 460 80 10 b2f
418 461 498 11
419 462 73 12
420 463 499 13 1f
421 464 499 14 2f
422 465 499 15 3f
423 466 161 16
424 467 161 19 b1f
425 468 162 20 center
426 469 162 21 area-1-east
427 470 162 22 area-2-north
428 471 162 23 area-3-west
429 472 147 24 1f
430 473 147 25 2f
431 474 147 26 b1f
432 475 87 27 1f
433 476 87 28 b1f
434 477 136 29 1f
435 478 136 30 b1f
436 479 136 31 b2f
437 480 136 32 b3f
438 481 136 33 b4f
439 482 160 34 3f
440 483 160 35 4f
441 484 160 36 5f
442 485 160 37 6f
443 486 160 38 7f
444 487 158 39
445 488 500 40
446 489 500 41 cave
447 490 500 42 inside
448 491 500 44 1f-cave-behind-team-rocket
449 492 500 45 b1f
450 493 500 46 b2f
451 494 500 47 b3f
452 495 501 50
453 496 502 51 entrance
454 497 502 52 1f
455 498 502 53 b1f
456 499 502 54 waterfall
457 500 503 55
458 501 504 56 room-1
459 502 504 57 room-2
460 503 504 58 room-3
461 504 504 59 room-4
462 505 504 60 room-5
463 506 504 61 room-6
464 507 504 62 room-7
465 508 504 63 room-8
466 509 504 64 room-9
467 510 504 65 room-10
468 511 504 66 item-rooms
469 512 505 70
470 513 506 71
471 514 507 72
472 515 508 73
473 516 509 74
474 517 510 75
475 518 511 76
476 519 512 77
477 520 513 78
478 521 514 79
479 522 515 80
480 523 516 81
481 524 517 82
482 525 518 83
483 526 519 84
484 527 520 85
485 528 521 86
486 529 88 87
487 530 99 88
488 531 109 89
489 532 120 90
490 533 130 91
491 534 131 92
492 535 132 93
493 536 133 94
494 537 134 95
495 538 89 96
496 539 90 97
497 540 91 98
498 541 92 99
499 542 93 100
500 543 94 101
501 544 95 102
502 545 96 103
503 546 97 104
504 547 522 105
505 548 523 106
506 549 524 107
507 550 102 109
508 551 157 110
509 552 103 111
510 553 104 112
511 554 86 113
512 555 154 114
513 556 68 115
514 557 525 116
515 558 67 117
516 559 76 118
517 560 71 119
518 561 526 120
519 562 527 121
520 563 528 122
521 564 529 123 a
522 565 529 124 b
523 566 529 125 c
524 567 529 126 d
525 568 529 127 e
526 569 529 128 f
527 570 529 129 g
528 571 529 130 h
529 572 529 131 i
530 573 530 13 1f
531 574 530 14 2f
532 575 530 15 3f

View file

@ -324,3 +324,118 @@ location_id,generation_id,game_index
341,4,3076
342,4,2013
343,4,2014
344,5,1
345,5,2
346,5,4
346,5,81
347,5,5
348,5,6
349,5,7
350,5,8
351,5,9
351,5,76
352,5,10
352,5,77
353,5,11
353,5,78
354,5,12
354,5,79
355,5,13
355,5,80
356,5,14
357,5,15
358,5,16
359,5,17
360,5,18
360,5,93
361,5,19
361,5,94
362,5,20
362,5,95
363,5,21
363,5,96
364,5,22
364,5,97
365,5,23
366,5,24
366,5,98
367,5,25
367,5,99
368,5,26
368,5,100
369,5,27
369,5,101
370,5,28
370,5,102
371,5,29
371,5,103
372,5,30
373,5,31
374,5,32
375,5,33
376,5,34
377,5,35
378,5,36
378,5,84
379,5,37
379,5,85
380,5,38
380,5,86
381,5,39
381,5,87
382,5,40
383,5,41
383,5,104
384,5,42
384,5,105
385,5,43
386,5,44
387,5,45
388,5,46
389,5,47
390,5,48
391,5,49
392,5,50
392,5,83
393,5,51
393,5,82
394,5,52
395,5,53
396,5,54
397,5,55
398,5,56
399,5,57
400,5,58
401,5,59
402,5,60
403,5,61
403,5,88
404,5,62
405,5,63
406,5,64
407,5,65
407,5,89
408,5,66
408,5,90
409,5,67
409,5,91
410,5,68
410,5,92
411,5,69
412,5,70
413,5,71
414,5,72
415,5,73
416,5,74
417,5,75
418,5,106
419,5,107
420,5,108
421,5,109
422,5,110
423,5,111
424,5,112
425,5,113
426,5,114
427,5,115
428,5,116

1 location_id generation_id game_index
324 341 4 3076
325 342 4 2013
326 343 4 2014
327 344 5 1
328 345 5 2
329 346 5 4
330 346 5 81
331 347 5 5
332 348 5 6
333 349 5 7
334 350 5 8
335 351 5 9
336 351 5 76
337 352 5 10
338 352 5 77
339 353 5 11
340 353 5 78
341 354 5 12
342 354 5 79
343 355 5 13
344 355 5 80
345 356 5 14
346 357 5 15
347 358 5 16
348 359 5 17
349 360 5 18
350 360 5 93
351 361 5 19
352 361 5 94
353 362 5 20
354 362 5 95
355 363 5 21
356 363 5 96
357 364 5 22
358 364 5 97
359 365 5 23
360 366 5 24
361 366 5 98
362 367 5 25
363 367 5 99
364 368 5 26
365 368 5 100
366 369 5 27
367 369 5 101
368 370 5 28
369 370 5 102
370 371 5 29
371 371 5 103
372 372 5 30
373 373 5 31
374 374 5 32
375 375 5 33
376 376 5 34
377 377 5 35
378 378 5 36
379 378 5 84
380 379 5 37
381 379 5 85
382 380 5 38
383 380 5 86
384 381 5 39
385 381 5 87
386 382 5 40
387 383 5 41
388 383 5 104
389 384 5 42
390 384 5 105
391 385 5 43
392 386 5 44
393 387 5 45
394 388 5 46
395 389 5 47
396 390 5 48
397 391 5 49
398 392 5 50
399 392 5 83
400 393 5 51
401 393 5 82
402 394 5 52
403 395 5 53
404 396 5 54
405 397 5 55
406 398 5 56
407 399 5 57
408 400 5 58
409 401 5 59
410 402 5 60
411 403 5 61
412 403 5 88
413 404 5 62
414 405 5 63
415 406 5 64
416 407 5 65
417 407 5 89
418 408 5 66
419 408 5 90
420 409 5 67
421 409 5 91
422 410 5 68
423 410 5 92
424 411 5 69
425 412 5 70
426 413 5 71
427 414 5 72
428 415 5 73
429 416 5 74
430 417 5 75
431 418 5 106
432 419 5 107
433 420 5 108
434 421 5 109
435 422 5 110
436 423 5 111
437 424 5 112
438 425 5 113
439 426 5 114
440 427 5 115
441 428 5 116

View file

@ -331,3 +331,275 @@ location_id,local_language_id,name
341,9,Concert Event
342,9,Mr. Pokémon
343,9,Primo
344,1,なぞの場所
344,9,Mystery Zone
345,1,遠い場所
345,9,Faraway place
346,1,カノコタウン
346,9,Nuvema Town
347,1,カラクサタウン
347,9,Accumula Town
348,1,サンヨウシティ
348,9,Striaton City
349,1,シッポウシティ
349,9,Nacrene City
350,1,ヒウンシティ
350,9,Castelia City
351,1,ライモンシティ
351,9,Nimbasa City
352,1,ホドモエシティ
352,9,Driftveil City
353,1,フキヨセシティ
353,9,Mistralton City
354,1,セッカシティ
354,9,Icirrus City
355,1,ソウリュウシティ
355,9,Opelucid City
356,1,1番道路
356,9,Route 1
357,1,2番道路
357,9,Route 2
358,1,3番道路
358,9,Route 3
359,1,4番道路
359,9,Route 4
360,1,5番道路
360,9,Route 5
361,1,6番道路
361,9,Route 6
362,1,7番道路
362,9,Route 7
363,1,8番道路
363,9,Route 8
364,1,9番道路
364,9,Route 9
365,1,10番道路
365,9,Route 10
366,1,11番道路
366,9,Route 11
367,1,12番道路
367,9,Route 12
368,1,13番道路
368,9,Route 13
369,1,14番道路
369,9,Route 14
370,1,15番道路
370,9,Route 15
371,1,16番道路
371,9,Route 16
372,1,17番水道
372,9,Route 17
373,1,18番道路
373,9,Route 18
374,1,夢の跡地
374,9,Dreamyard
375,1,ヤグルマの森
375,9,Pinwheel Forest
376,1,リゾートデザート
376,9,Desert Resort
377,1,古代の城
377,9,Relic Castle
378,1,冷凍コンテナ
378,9,Cold Storage
379,1,電気石の洞穴
379,9,Chargestone Cave
380,1,ネジ山
380,9,Twist Mountain
381,1,リュウラセンの塔
381,9,Dragonspiral Tower
382,1,チャンピオンロード
382,9,Victory Road
383,1,カゴメタウン
383,9,Lacunosa Town
384,1,サザナミタウン
384,9,Undella Town
385,1,カナワタウン
385,9,Anville Town
386,1,ポケモンリーグ
386,9,Pokémon League
387,1,Nの城
387,9,N's Castle
388,1,ロイヤルイッシュ号
388,9,Royal Unova
389,1,ギアステーション
389,9,Gear Station
390,1,バトルサブウェイ
390,9,Battle Subway
391,1,ミュージカルホール
391,9,Musical Theater
392,1,ブラックシティ
392,9,Black City
393,1,ホワイトフォレスト
393,9,White Forest
394,1,ユナイテッドタワー
394,9,Unity Tower
395,1,地下水脈の穴
395,9,Wellspring Cave
396,1,フキヨセの洞穴
396,9,Mistralton Cave
397,1,思索の原
397,9,Rumination Field
398,1,タワーオブヘブン
398,9,Celestial Tower
399,1,セッカの湿原
399,9,Moor of Icirrus
400,1,ショッピングモール
400,9,Shopping Mall
401,1,修行の岩屋
401,9,Challenger's Cave
402,1,シフトファクトリー
402,9,Poké Transfer Lab
403,1,ジャイアントホール
403,9,Giant Chasm
404,1,リバティガーデン島
404,9,Liberty Garden
405,1,P2ラボ
405,9,P2 Laboratory
406,1,スカイアローブリッジ
406,9,Skyarrow Bridge
407,1,ホドモエの跳ね橋
407,9,Driftveil Drawbridge
408,1,シリンダーブリッジ
408,9,Tubeline Bridge
409,1,ビレッジブリッジ
409,9,Village Bridge
410,1,ワンダーブリッジ
410,9,Marvelous Bridge
411,1,ハイリンク
411,9,Entralink
412,1,ほうじょうの社
412,9,Abundant Shrine
413,1,サザナミ湾
413,9,Undella Bay
414,1,迷いの森
414,9,Lostlorn Forest
415,1,試練の室
415,9,Trial Chamber
416,1,導の間
416,9,Guidance Chamber
417,1,ハイリンクの森
417,9,Entree Forest
418,1,カラクサゲート
418,9,Accumula Gate
419,1,サザナミゲート
419,9,Undella Gate
420,1,シッポウゲート
420,9,Nacrene Gate
421,1,ヒウンゲート
421,9,Castelia Gate
422,1,ライモンゲート
422,9,Nimbasa Gate
423,1,ソウリュウゲート
423,9,Opelucid Gate
424,1,ブラックゲート
424,9,Black Gate
425,1,ホワイトゲート
425,9,White Gate
426,1,ブリッジゲート
426,9,Bridge Gate
427,1,ロードゲート
427,9,Route Gate
428,1,海底遺跡
428,9,Abyssal Ruins
429,9,Petalburg City
430,9,Slateport City
431,9,Lilycove City
432,9,Mossdeep City
433,9,Sootopolis City
434,9,Ever Grande City
435,9,Meteor Falls
436,9,Rusturf Tunnel
437,9,Granite Cave
438,9,Petalburg Woods
439,9,Jagged Pass
440,9,Fiery Pass
441,9,Mt. Pyre
442,9,Seafloor Cavern
443,9,Cave of Origin
444,9,Victory Road
445,9,Shoal Cave
446,9,New Mauville
447,9,Abandoned Ship
448,9,Sky Pillar
449,9,Route 101
450,9,Route 102
451,9,Route 103
452,9,Route 104
453,9,Route 105
454,9,Route 106
455,9,Route 107
456,9,Route 108
457,9,Route 109
458,9,Route 110
459,9,Route 111
460,9,Route 112
461,9,Route 113
462,9,Route 114
463,9,Route 115
464,9,Route 116
465,9,Route 117
466,9,Route 118
467,9,Route 119
468,9,Route 120
469,9,Route 121
470,9,Route 122
471,9,Route 123
472,9,Route 124
473,9,Route 125
474,9,Route 126
475,9,Route 127
476,9,Route 128
477,9,Route 129
478,9,Route 130
479,9,Route 131
480,9,Route 132
481,9,Route 133
482,9,Route 134
483,9,Safari Zone
484,9,Dewford Town
485,9,Pacifidlog Town
486,9,Magma Hideout
487,9,Mirage Tower
488,9,Desert Underpass
489,9,Artisan Cave
490,9,Altering Cave
491,9,Monean Chamber
492,9,Liptoo Chamber
493,9,Weepth Chamber
494,9,Dilford Chamber
495,9,Scufib Chamber
496,9,Rixy Chamber
497,9,Viapos Chamber
498,9,S.S. Anne
499,9,Victory Road
500,9,Mt. Ember
501,9,Berry Forest
502,9,Icefall Cave
503,9,Patern Bush
504,9,Lost Cave
505,9,Kindle Road
506,9,Treasure Beach
507,9,Cape Brink
508,9,Bond Bridge
509,9,Three Isle Port
510,9,Resort Gorgeous
511,9,Water Labyrinth
512,9,Five Isle Meadow
513,9,Memorial Pillar
514,9,Outcast Island
515,9,Green Path
516,9,Water Path
517,9,Ruin Valley
518,9,Trainer Tower
519,9,Canyon Entrance
520,9,Sevault Canyon
521,9,Tanoby Ruins
522,9,Route 19
523,9,Route 20
524,9,Route 21
525,9,Vermillion City
526,9,One Island
527,9,Four Island
528,9,Five Island
529,9,Altering Cave
530,9,Victory Road

1 location_id local_language_id name
331 341 9 Concert Event
332 342 9 Mr. Pokémon
333 343 9 Primo
334 344 1 なぞの場所
335 344 9 Mystery Zone
336 345 1 遠い場所
337 345 9 Faraway place
338 346 1 カノコタウン
339 346 9 Nuvema Town
340 347 1 カラクサタウン
341 347 9 Accumula Town
342 348 1 サンヨウシティ
343 348 9 Striaton City
344 349 1 シッポウシティ
345 349 9 Nacrene City
346 350 1 ヒウンシティ
347 350 9 Castelia City
348 351 1 ライモンシティ
349 351 9 Nimbasa City
350 352 1 ホドモエシティ
351 352 9 Driftveil City
352 353 1 フキヨセシティ
353 353 9 Mistralton City
354 354 1 セッカシティ
355 354 9 Icirrus City
356 355 1 ソウリュウシティ
357 355 9 Opelucid City
358 356 1 1番道路
359 356 9 Route 1
360 357 1 2番道路
361 357 9 Route 2
362 358 1 3番道路
363 358 9 Route 3
364 359 1 4番道路
365 359 9 Route 4
366 360 1 5番道路
367 360 9 Route 5
368 361 1 6番道路
369 361 9 Route 6
370 362 1 7番道路
371 362 9 Route 7
372 363 1 8番道路
373 363 9 Route 8
374 364 1 9番道路
375 364 9 Route 9
376 365 1 10番道路
377 365 9 Route 10
378 366 1 11番道路
379 366 9 Route 11
380 367 1 12番道路
381 367 9 Route 12
382 368 1 13番道路
383 368 9 Route 13
384 369 1 14番道路
385 369 9 Route 14
386 370 1 15番道路
387 370 9 Route 15
388 371 1 16番道路
389 371 9 Route 16
390 372 1 17番水道
391 372 9 Route 17
392 373 1 18番道路
393 373 9 Route 18
394 374 1 夢の跡地
395 374 9 Dreamyard
396 375 1 ヤグルマの森
397 375 9 Pinwheel Forest
398 376 1 リゾートデザート
399 376 9 Desert Resort
400 377 1 古代の城
401 377 9 Relic Castle
402 378 1 冷凍コンテナ
403 378 9 Cold Storage
404 379 1 電気石の洞穴
405 379 9 Chargestone Cave
406 380 1 ネジ山
407 380 9 Twist Mountain
408 381 1 リュウラセンの塔
409 381 9 Dragonspiral Tower
410 382 1 チャンピオンロード
411 382 9 Victory Road
412 383 1 カゴメタウン
413 383 9 Lacunosa Town
414 384 1 サザナミタウン
415 384 9 Undella Town
416 385 1 カナワタウン
417 385 9 Anville Town
418 386 1 ポケモンリーグ
419 386 9 Pokémon League
420 387 1 Nの城
421 387 9 N's Castle
422 388 1 ロイヤルイッシュ号
423 388 9 Royal Unova
424 389 1 ギアステーション
425 389 9 Gear Station
426 390 1 バトルサブウェイ
427 390 9 Battle Subway
428 391 1 ミュージカルホール
429 391 9 Musical Theater
430 392 1 ブラックシティ
431 392 9 Black City
432 393 1 ホワイトフォレスト
433 393 9 White Forest
434 394 1 ユナイテッドタワー
435 394 9 Unity Tower
436 395 1 地下水脈の穴
437 395 9 Wellspring Cave
438 396 1 フキヨセの洞穴
439 396 9 Mistralton Cave
440 397 1 思索の原
441 397 9 Rumination Field
442 398 1 タワーオブヘブン
443 398 9 Celestial Tower
444 399 1 セッカの湿原
445 399 9 Moor of Icirrus
446 400 1 ショッピングモール
447 400 9 Shopping Mall
448 401 1 修行の岩屋
449 401 9 Challenger's Cave
450 402 1 シフトファクトリー
451 402 9 Poké Transfer Lab
452 403 1 ジャイアントホール
453 403 9 Giant Chasm
454 404 1 リバティガーデン島
455 404 9 Liberty Garden
456 405 1 P2ラボ
457 405 9 P2 Laboratory
458 406 1 スカイアローブリッジ
459 406 9 Skyarrow Bridge
460 407 1 ホドモエの跳ね橋
461 407 9 Driftveil Drawbridge
462 408 1 シリンダーブリッジ
463 408 9 Tubeline Bridge
464 409 1 ビレッジブリッジ
465 409 9 Village Bridge
466 410 1 ワンダーブリッジ
467 410 9 Marvelous Bridge
468 411 1 ハイリンク
469 411 9 Entralink
470 412 1 ほうじょうの社
471 412 9 Abundant Shrine
472 413 1 サザナミ湾
473 413 9 Undella Bay
474 414 1 迷いの森
475 414 9 Lostlorn Forest
476 415 1 試練の室
477 415 9 Trial Chamber
478 416 1 導の間
479 416 9 Guidance Chamber
480 417 1 ハイリンクの森
481 417 9 Entree Forest
482 418 1 カラクサゲート
483 418 9 Accumula Gate
484 419 1 サザナミゲート
485 419 9 Undella Gate
486 420 1 シッポウゲート
487 420 9 Nacrene Gate
488 421 1 ヒウンゲート
489 421 9 Castelia Gate
490 422 1 ライモンゲート
491 422 9 Nimbasa Gate
492 423 1 ソウリュウゲート
493 423 9 Opelucid Gate
494 424 1 ブラックゲート
495 424 9 Black Gate
496 425 1 ホワイトゲート
497 425 9 White Gate
498 426 1 ブリッジゲート
499 426 9 Bridge Gate
500 427 1 ロードゲート
501 427 9 Route Gate
502 428 1 海底遺跡
503 428 9 Abyssal Ruins
504 429 9 Petalburg City
505 430 9 Slateport City
506 431 9 Lilycove City
507 432 9 Mossdeep City
508 433 9 Sootopolis City
509 434 9 Ever Grande City
510 435 9 Meteor Falls
511 436 9 Rusturf Tunnel
512 437 9 Granite Cave
513 438 9 Petalburg Woods
514 439 9 Jagged Pass
515 440 9 Fiery Pass
516 441 9 Mt. Pyre
517 442 9 Seafloor Cavern
518 443 9 Cave of Origin
519 444 9 Victory Road
520 445 9 Shoal Cave
521 446 9 New Mauville
522 447 9 Abandoned Ship
523 448 9 Sky Pillar
524 449 9 Route 101
525 450 9 Route 102
526 451 9 Route 103
527 452 9 Route 104
528 453 9 Route 105
529 454 9 Route 106
530 455 9 Route 107
531 456 9 Route 108
532 457 9 Route 109
533 458 9 Route 110
534 459 9 Route 111
535 460 9 Route 112
536 461 9 Route 113
537 462 9 Route 114
538 463 9 Route 115
539 464 9 Route 116
540 465 9 Route 117
541 466 9 Route 118
542 467 9 Route 119
543 468 9 Route 120
544 469 9 Route 121
545 470 9 Route 122
546 471 9 Route 123
547 472 9 Route 124
548 473 9 Route 125
549 474 9 Route 126
550 475 9 Route 127
551 476 9 Route 128
552 477 9 Route 129
553 478 9 Route 130
554 479 9 Route 131
555 480 9 Route 132
556 481 9 Route 133
557 482 9 Route 134
558 483 9 Safari Zone
559 484 9 Dewford Town
560 485 9 Pacifidlog Town
561 486 9 Magma Hideout
562 487 9 Mirage Tower
563 488 9 Desert Underpass
564 489 9 Artisan Cave
565 490 9 Altering Cave
566 491 9 Monean Chamber
567 492 9 Liptoo Chamber
568 493 9 Weepth Chamber
569 494 9 Dilford Chamber
570 495 9 Scufib Chamber
571 496 9 Rixy Chamber
572 497 9 Viapos Chamber
573 498 9 S.S. Anne
574 499 9 Victory Road
575 500 9 Mt. Ember
576 501 9 Berry Forest
577 502 9 Icefall Cave
578 503 9 Patern Bush
579 504 9 Lost Cave
580 505 9 Kindle Road
581 506 9 Treasure Beach
582 507 9 Cape Brink
583 508 9 Bond Bridge
584 509 9 Three Isle Port
585 510 9 Resort Gorgeous
586 511 9 Water Labyrinth
587 512 9 Five Isle Meadow
588 513 9 Memorial Pillar
589 514 9 Outcast Island
590 515 9 Green Path
591 516 9 Water Path
592 517 9 Ruin Valley
593 518 9 Trainer Tower
594 519 9 Canyon Entrance
595 520 9 Sevault Canyon
596 521 9 Tanoby Ruins
597 522 9 Route 19
598 523 9 Route 20
599 524 9 Route 21
600 525 9 Vermillion City
601 526 9 One Island
602 527 9 Four Island
603 528 9 Five Island
604 529 9 Altering Cave
605 530 9 Victory Road

View file

@ -331,3 +331,190 @@ id,region_id,identifier
341,,concert-event
342,,mr-pokemon
343,,primo
344,5,mystery-zone
345,5,faraway-place
346,5,nuvema-town
347,5,accumula-town
348,5,striaton-city
349,5,nacrene-city
350,5,castelia-city
351,5,nimbasa-city
352,5,driftveil-city
353,5,mistralton-city
354,5,icirrus-city
355,5,opelucid-city
356,5,route-1
357,5,route-2
358,5,route-3
359,5,route-4
360,5,route-5
361,5,route-6
362,5,route-7
363,5,route-8
364,5,route-9
365,5,route-10
366,5,route-11
367,5,route-12
368,5,route-13
369,5,route-14
370,5,route-15
371,5,route-16
372,5,route-17
373,5,route-18
374,5,dreamyard
375,5,pinwheel-forest
376,5,desert-resort
377,5,relic-castle
378,5,cold-storage
379,5,chargestone-cave
380,5,twist-mountain
381,5,dragonspiral-tower
382,5,victory-road
383,5,lacunosa-town
384,5,undella-town
385,5,anville-town
386,5,pokemon-league
387,5,ns-castle
388,5,royal-unova
389,5,gear-station
390,5,battle-subway
391,5,musical-theater
392,5,black-city
393,5,white-forest
394,5,unity-tower
395,5,wellspring-cave
396,5,mistralton-cave
397,5,rumination-field
398,5,celestial-tower
399,5,moor-of-icirrus
400,5,shopping-mall
401,5,challengers-cave
402,5,poke-transfer-lab
403,5,giant-chasm
404,5,liberty-garden
405,5,p2-laboratory
406,5,skyarrow-bridge
407,5,driftveil-drawbridge
408,5,tubeline-bridge
409,5,village-bridge
410,5,marvelous-bridge
411,5,entralink
412,5,abundant-shrine
413,5,undella-bay
414,5,lostlorn-forest
415,5,trial-chamber
416,5,guidance-chamber
417,5,entree-forest
418,5,accumula-gate
419,5,undella-gate
420,5,nacrene-gate
421,5,castelia-gate
422,5,nimbasa-gate
423,5,opelucid-gate
424,5,black-gate
425,5,white-gate
426,5,bridge-gate
427,5,route-gate
428,5,abyssal-ruins
429,3,petalburg-city
430,3,slateport-city
431,3,lilycove-city
432,3,mossdeep-city
433,3,sootopolis-city
434,3,ever-grande-city
435,3,meteor-falls
436,3,rusturf-tunnel
437,3,granite-cave
438,3,petalburg-woods
439,3,jagged-pass
440,3,fiery-pass
441,3,mt-pyre
442,3,seafloor-cavern
443,3,cave-of-origin
444,3,victory-road
445,3,shoal-cave
446,3,new-mauville
447,3,abandoned-ship
448,3,sky-pillar
449,3,route-101
450,3,route-102
451,3,route-103
452,3,route-104
453,3,route-105
454,3,route-106
455,3,route-107
456,3,route-108
457,3,route-109
458,3,route-110
459,3,route-111
460,3,route-112
461,3,route-113
462,3,route-114
463,3,route-115
464,3,route-116
465,3,route-117
466,3,route-118
467,3,route-119
468,3,route-120
469,3,route-121
470,3,route-122
471,3,route-123
472,3,route-124
473,3,route-125
474,3,route-126
475,3,route-127
476,3,route-128
477,3,route-129
478,3,route-130
479,3,route-131
480,3,route-132
481,3,route-133
482,3,route-134
483,3,safari-zone
484,3,dewford-town
485,3,pacifidlog-town
486,3,magma-hideout
487,3,mirage-tower
488,3,desert-underpass
489,3,artisan-cave
490,3,altering-cave
491,1,monean-chamber
492,1,liptoo-chamber
493,1,weepth-chamber
494,1,dilford-chamber
495,1,scufib-chamber
496,1,rixy-chamber
497,1,viapos-chamber
498,1,ss-anne
499,1,victory-road
500,1,mt-ember
501,1,berry-forest
502,1,icefall-cave
503,1,patern-bush
504,1,lost-cave
505,1,kindle-road
506,1,treasure-beach
507,1,cape-brink
508,1,bond-bridge
509,1,three-isle-port
510,1,resort-gorgeous
511,1,water-labyrinth
512,1,five-isle-meadow
513,1,memorial-pillar
514,1,outcast-island
515,1,green-path
516,1,water-path
517,1,ruin-valley
518,1,trainer-tower
519,1,canyon-entrance
520,1,sevault-canyon
521,1,tanoby-ruins
522,1,route-19
523,1,route-20
524,1,route-21
525,1,vermillion-city
526,1,one-island
527,1,four-island
528,1,five-island
529,1,altering-cave
530,1,victory-road

1 id region_id identifier
331 341 concert-event
332 342 mr-pokemon
333 343 primo
334 344 5 mystery-zone
335 345 5 faraway-place
336 346 5 nuvema-town
337 347 5 accumula-town
338 348 5 striaton-city
339 349 5 nacrene-city
340 350 5 castelia-city
341 351 5 nimbasa-city
342 352 5 driftveil-city
343 353 5 mistralton-city
344 354 5 icirrus-city
345 355 5 opelucid-city
346 356 5 route-1
347 357 5 route-2
348 358 5 route-3
349 359 5 route-4
350 360 5 route-5
351 361 5 route-6
352 362 5 route-7
353 363 5 route-8
354 364 5 route-9
355 365 5 route-10
356 366 5 route-11
357 367 5 route-12
358 368 5 route-13
359 369 5 route-14
360 370 5 route-15
361 371 5 route-16
362 372 5 route-17
363 373 5 route-18
364 374 5 dreamyard
365 375 5 pinwheel-forest
366 376 5 desert-resort
367 377 5 relic-castle
368 378 5 cold-storage
369 379 5 chargestone-cave
370 380 5 twist-mountain
371 381 5 dragonspiral-tower
372 382 5 victory-road
373 383 5 lacunosa-town
374 384 5 undella-town
375 385 5 anville-town
376 386 5 pokemon-league
377 387 5 ns-castle
378 388 5 royal-unova
379 389 5 gear-station
380 390 5 battle-subway
381 391 5 musical-theater
382 392 5 black-city
383 393 5 white-forest
384 394 5 unity-tower
385 395 5 wellspring-cave
386 396 5 mistralton-cave
387 397 5 rumination-field
388 398 5 celestial-tower
389 399 5 moor-of-icirrus
390 400 5 shopping-mall
391 401 5 challengers-cave
392 402 5 poke-transfer-lab
393 403 5 giant-chasm
394 404 5 liberty-garden
395 405 5 p2-laboratory
396 406 5 skyarrow-bridge
397 407 5 driftveil-drawbridge
398 408 5 tubeline-bridge
399 409 5 village-bridge
400 410 5 marvelous-bridge
401 411 5 entralink
402 412 5 abundant-shrine
403 413 5 undella-bay
404 414 5 lostlorn-forest
405 415 5 trial-chamber
406 416 5 guidance-chamber
407 417 5 entree-forest
408 418 5 accumula-gate
409 419 5 undella-gate
410 420 5 nacrene-gate
411 421 5 castelia-gate
412 422 5 nimbasa-gate
413 423 5 opelucid-gate
414 424 5 black-gate
415 425 5 white-gate
416 426 5 bridge-gate
417 427 5 route-gate
418 428 5 abyssal-ruins
419 429 3 petalburg-city
420 430 3 slateport-city
421 431 3 lilycove-city
422 432 3 mossdeep-city
423 433 3 sootopolis-city
424 434 3 ever-grande-city
425 435 3 meteor-falls
426 436 3 rusturf-tunnel
427 437 3 granite-cave
428 438 3 petalburg-woods
429 439 3 jagged-pass
430 440 3 fiery-pass
431 441 3 mt-pyre
432 442 3 seafloor-cavern
433 443 3 cave-of-origin
434 444 3 victory-road
435 445 3 shoal-cave
436 446 3 new-mauville
437 447 3 abandoned-ship
438 448 3 sky-pillar
439 449 3 route-101
440 450 3 route-102
441 451 3 route-103
442 452 3 route-104
443 453 3 route-105
444 454 3 route-106
445 455 3 route-107
446 456 3 route-108
447 457 3 route-109
448 458 3 route-110
449 459 3 route-111
450 460 3 route-112
451 461 3 route-113
452 462 3 route-114
453 463 3 route-115
454 464 3 route-116
455 465 3 route-117
456 466 3 route-118
457 467 3 route-119
458 468 3 route-120
459 469 3 route-121
460 470 3 route-122
461 471 3 route-123
462 472 3 route-124
463 473 3 route-125
464 474 3 route-126
465 475 3 route-127
466 476 3 route-128
467 477 3 route-129
468 478 3 route-130
469 479 3 route-131
470 480 3 route-132
471 481 3 route-133
472 482 3 route-134
473 483 3 safari-zone
474 484 3 dewford-town
475 485 3 pacifidlog-town
476 486 3 magma-hideout
477 487 3 mirage-tower
478 488 3 desert-underpass
479 489 3 artisan-cave
480 490 3 altering-cave
481 491 1 monean-chamber
482 492 1 liptoo-chamber
483 493 1 weepth-chamber
484 494 1 dilford-chamber
485 495 1 scufib-chamber
486 496 1 rixy-chamber
487 497 1 viapos-chamber
488 498 1 ss-anne
489 499 1 victory-road
490 500 1 mt-ember
491 501 1 berry-forest
492 502 1 icefall-cave
493 503 1 patern-bush
494 504 1 lost-cave
495 505 1 kindle-road
496 506 1 treasure-beach
497 507 1 cape-brink
498 508 1 bond-bridge
499 509 1 three-isle-port
500 510 1 resort-gorgeous
501 511 1 water-labyrinth
502 512 1 five-isle-meadow
503 513 1 memorial-pillar
504 514 1 outcast-island
505 515 1 green-path
506 516 1 water-path
507 517 1 ruin-valley
508 518 1 trainer-tower
509 519 1 canyon-entrance
510 520 1 sevault-canyon
511 521 1 tanoby-ruins
512 522 1 route-19
513 523 1 route-20
514 524 1 route-21
515 525 1 vermillion-city
516 526 1 one-island
517 527 1 four-island
518 528 1 five-island
519 529 1 altering-cave
520 530 1 victory-road

View file

@ -4,8 +4,8 @@ id,identifier
3,tutor
4,machine
5,stadium-surfing-pikachu
6,volt-tackle-pichu
6,light-ball-egg
7,colosseum-purification
8,xd-shadow
9,xd-purification
10,rotom-form
10,form-change

1 id identifier
4 3 tutor
5 4 machine
6 5 stadium-surfing-pikachu
7 6 volt-tackle-pichu light-ball-egg
8 7 colosseum-purification
9 8 xd-shadow
10 9 xd-purification
11 10 rotom-form form-change

View file

@ -1,3 +1,6 @@
# encoding: utf-8
import re
from sqlalchemy import engine_from_config, orm
from ..defaults import get_default_db_uri
@ -21,7 +24,7 @@ def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
uri = get_default_db_uri()
### Do some fixery for MySQL
if uri[0:5] == 'mysql':
if uri.startswith('mysql:'):
# MySQL uses latin1 for connections by default even if the server is
# otherwise oozing with utf8; charset fixes this
if 'charset' not in uri:
@ -51,3 +54,33 @@ def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
session._default_language_id = 9
return session
def identifier_from_name(name):
"""Make a string safe to use as an identifier.
Valid characters are lowercase alphanumerics and "-". This function may
raise ValueError if it can't come up with a suitable identifier.
This function is useful for scripts which add things with names.
"""
if isinstance(name, str):
identifier = name.decode('utf-8')
else:
identifier = name
identifier = identifier.lower()
identifier = identifier.replace(u'+', u' plus ')
identifier = re.sub(u'[ _]+', u'-', identifier)
identifier = re.sub(u"['./;(),:]", u'', identifier)
identifier = identifier.replace(u'é', u'e')
identifier = identifier.replace(u'', u'-f')
identifier = identifier.replace(u'', u'-m')
if identifier in (u'???', u'????'):
identifier = u'unknown'
elif identifier == u'!':
identifier = u'exclamation'
elif identifier == u'?':
identifier = u'question'
if not identifier.replace(u"-", u"").isalnum():
raise ValueError(identifier)
return identifier

View file

@ -0,0 +1,54 @@
import sqlalchemy.sql.visitors as visitors
from pokedex.db.tables import metadata
# stolen from sqlalchemy.sql.util.sort_tables
def compute_dependencies(tables):
"""Construct a reverse dependency graph for the given tables.
Returns a dict which maps a table to the list of tables which depend on it.
"""
tables = list(tables)
graph = {}
def visit_foreign_key(fkey):
if fkey.use_alter:
return
parent_table = fkey.column.table
if parent_table in tables:
child_table = fkey.parent.table
if parent_table is not child_table:
graph.setdefault(parent_table, []).append(child_table)
for table in tables:
visitors.traverse(table,
{'schema_visitor': True},
{'foreign_key': visit_foreign_key})
graph.setdefault(table, []).extend(table._extra_dependencies)
return graph
#: The dependency graph for pokedex.db.tables
_pokedex_graph = compute_dependencies(metadata.tables.values())
def find_dependent_tables(tables, graph=None):
"""Recursively find all tables which depend on the given tables.
The returned set does not include the original tables.
"""
if graph is None:
graph = _pokedex_graph
tables = list(tables)
dependents = set()
def add_dependents_of(table):
for dependent_table in graph.get(table, []):
if dependent_table not in dependents:
dependents.add(dependent_table)
add_dependents_of(dependent_table)
for table in tables:
add_dependents_of(table)
dependents -= set(tables)
return dependents

View file

@ -11,6 +11,7 @@ import sqlalchemy.types
from pokedex.db import metadata
import pokedex.db.tables as tables
from pokedex.defaults import get_default_csv_dir
from pokedex.db.dependencies import find_dependent_tables
def _get_table_names(metadata, patterns):
@ -52,7 +53,7 @@ def _get_verbose_prints(verbose):
def print_start(thing):
# Truncate to 66 characters, leaving 10 characters for a success
# or failure message
truncated_thing = thing[0:66]
truncated_thing = thing[:66]
# Also, space-pad to keep the cursor in a known column
num_spaces = 66 - len(truncated_thing)
@ -95,7 +96,7 @@ def _get_verbose_prints(verbose):
return print_start, print_status, print_done
def load(session, tables=[], directory=None, drop_tables=False, verbose=False, safe=True):
def load(session, tables=[], directory=None, drop_tables=False, verbose=False, safe=True, recursive=False):
"""Load data from CSV files into the given database session.
Tables are created automatically.
@ -119,6 +120,9 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
`safe`
If set to False, load can be faster, but can corrupt the database if
it crashes or is interrupted.
`recursive`
If set to True, load all dependent tables too.
"""
# First take care of verbosity
@ -128,8 +132,13 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
if directory is None:
directory = get_default_csv_dir()
# XXX why isn't this done in command_load
table_names = _get_table_names(metadata, tables)
table_objs = [metadata.tables[name] for name in table_names]
if recursive:
table_objs.extend(find_dependent_tables(table_objs))
table_objs = sqlalchemy.sql.util.sort_tables(table_objs)
# SQLite speed tweaks
@ -185,15 +194,15 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
force_not_null = 'FORCE NOT NULL ' + ','.join('"%s"' % c for c in not_null_cols)
else:
force_not_null = ''
command = "COPY {table_name} ({columns}) FROM '{csvpath}' CSV HEADER {force_not_null}"
command = "COPY %(table_name)s (%(columns)s) FROM '%(csvpath)s' CSV HEADER %(force_not_null)s"
session.connection().execute(
command.format(
table_name=table_name,
csvpath=csvpath,
columns=','.join('"%s"' % c for c in column_names),
force_not_null=force_not_null,
)
command % dict(
table_name=table_name,
csvpath=csvpath,
columns=','.join('"%s"' % c for c in column_names),
force_not_null=force_not_null,
)
)
session.commit()
print_done()
continue
@ -203,12 +212,12 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
# them to the session last
# ASSUMPTION: Self-referential tables have a single PK called "id"
deferred_rows = [] # ( row referring to id, [foreign ids we need] )
seen_ids = {} # primary key we've seen => 1
seen_ids = set() # primary keys we've seen
# Fetch foreign key columns that point at this table, if any
self_ref_columns = []
for column in table_obj.c:
if any(_.references(table_obj) for _ in column.foreign_keys):
if any(x.references(table_obj) for x in column.foreign_keys):
self_ref_columns.append(column)
new_rows = []
@ -247,18 +256,18 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
# May need to stash this row and add it later if it refers to a
# later row in this table
if self_ref_columns:
foreign_ids = [row_data[_.name] for _ in self_ref_columns]
foreign_ids = [_ for _ in foreign_ids if _] # remove NULL ids
foreign_ids = set(row_data[x.name] for x in self_ref_columns)
foreign_ids.discard(None) # remove NULL ids
if not foreign_ids:
# NULL key. Remember this row and add as usual.
seen_ids[row_data['id']] = 1
seen_ids.add(row_data['id'])
elif all(_ in seen_ids for _ in foreign_ids):
elif foreign_ids.issubset(seen_ids):
# Non-NULL key we've already seen. Remember it and commit
# so we know the old row exists when we add the new one
insert_and_commit()
seen_ids[row_data['id']] = 1
seen_ids.add(row_data['id'])
else:
# Non-NULL future id. Save this and insert it later!
@ -277,7 +286,7 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
# Attempt to add any spare rows we've collected
for row_data, foreign_ids in deferred_rows:
if not all(_ in seen_ids for _ in foreign_ids):
if not foreign_ids.issubset(seen_ids):
# Could happen if row A refers to B which refers to C.
# This is ridiculous and doesn't happen in my data so far
raise ValueError("Too many levels of self-reference! "

View file

@ -31,11 +31,17 @@ class MarkdownString(object):
def __unicode__(self):
return self.source_text
def __str__(self):
return unicode(self.source_text).encode()
def __html__(self):
return self.as_html
@property
def as_html(self):
"""Returns the string as HTML4."""
if self._as_html:
if self._as_html is not None:
return self._as_html
md = markdown.Markdown(

View file

@ -84,7 +84,7 @@ class Language(TableBase):
"""
__tablename__ = 'languages'
__singlename__ = 'language'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
iso639 = Column(Unicode(2), nullable=False,
info=dict(description="The two-letter code of the country where this language is spoken. Note that it is not unique.", format='identifier'))
@ -111,7 +111,7 @@ class Ability(TableBase):
"""
__tablename__ = 'abilities'
__singlename__ = 'ability'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="This ability's unique ID; matches the games' internal ID"))
identifier = Column(Unicode(24), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -134,7 +134,7 @@ class AbilityChangelog(TableBase):
"""History of changes to abilities across main game versions."""
__tablename__ = 'ability_changelog'
__singlename__ = 'ability_changelog'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="This change's unique ID"))
ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
info=dict(description="The ID of the ability that changed"))
@ -154,7 +154,7 @@ class AbilityFlavorText(TableBase):
info=dict(description="The ID of the ability"))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="The ID of the version group this flavor text is taken from"))
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
info=dict(description="The language"))
flavor_text = Column(Unicode(64), nullable=False,
info=dict(description="The actual flavor text", official=True, format='gametext'))
@ -165,7 +165,7 @@ class Berry(TableBase):
For data common to all items, such as the name, see the corresponding item entry.
"""
__tablename__ = 'berries'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="This Berry's in-game number"))
item_id = Column(Integer, ForeignKey('items.id'), nullable=False,
info=dict(description="The ID of the item that represents this Berry"))
@ -191,7 +191,7 @@ class BerryFirmness(TableBase):
"""
__tablename__ = 'berry_firmness'
__singlename__ = 'berry_firmness'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this firmness"))
identifier = Column(Unicode(10), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -227,7 +227,7 @@ class ContestEffect(TableBase):
"""
__tablename__ = 'contest_effects'
__singlename__ = 'contest_effect'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this effect"))
appeal = Column(SmallInteger, nullable=False,
info=dict(description="The base number of hearts the user of this move gets"))
@ -246,7 +246,7 @@ class ContestType(TableBase):
"""
__tablename__ = 'contest_types'
__singlename__ = 'contest_type'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this Contest type"))
identifier = Column(Unicode(6), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -268,7 +268,7 @@ class EggGroup(TableBase):
"""
__tablename__ = 'egg_groups'
__singlename__ = 'egg_group'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this group"))
identifier = Column(Unicode(16), nullable=False,
info=dict(description=u"An identifier.", format='identifier'))
@ -288,10 +288,10 @@ class Encounter(TableBase):
"slot" they are in and the state of the game world.
What the player is doing to get an encounter, such as surfing or walking
through tall grass, is called terrain. Each terrain has its own set of
through tall grass, is called a method. Each method has its own set of
encounter slots.
Within a terrain, slots are defined primarily by rarity. Each slot can
Within a method, slots are defined primarily by rarity. Each slot can
also be affected by world conditions; for example, the 20% slot for walking
in tall grass is affected by whether a swarm is in effect in that area.
"Is there a swarm?" is a condition; "there is a swarm" and "there is not a
@ -304,14 +304,14 @@ class Encounter(TableBase):
"""
__tablename__ = 'encounters'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this encounter"))
version_id = Column(Integer, ForeignKey('versions.id'), nullable=False, autoincrement=False,
info=dict(description="The ID of the version this applies to"))
location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False,
info=dict(description="The ID of the location of this encounter"))
encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), nullable=False, autoincrement=False,
info=dict(description="The ID of the encounter slot, which determines terrain and rarity"))
info=dict(description="The ID of the encounter slot, which determines method and rarity"))
pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
info=dict(description=u"The ID of the encountered Pokémon"))
min_level = Column(Integer, nullable=False, autoincrement=False,
@ -325,7 +325,7 @@ class EncounterCondition(TableBase):
__tablename__ = 'encounter_conditions'
__singlename__ = 'encounter_condition'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this condition"))
identifier = Column(Unicode(64), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -341,7 +341,7 @@ class EncounterConditionValue(TableBase):
__tablename__ = 'encounter_condition_values'
__singlename__ = 'encounter_condition_value'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
encounter_condition_id = Column(Integer, ForeignKey('encounter_conditions.id'), primary_key=False, nullable=False, autoincrement=False,
info=dict(description="The ID of the encounter condition this is a value of"))
@ -364,46 +364,46 @@ class EncounterConditionValueMap(TableBase):
encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="The ID of the encounter condition value"))
class EncounterMethod(TableBase):
u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
"""
__tablename__ = 'encounter_methods'
__singlename__ = 'encounter_method'
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for the method"))
identifier = Column(Unicode(16), nullable=False, unique=True,
info=dict(description="An identifier", format='identifier'))
create_translation_table('encounter_method_prose', EncounterMethod, 'prose',
name = Column(Unicode(64), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=False)),
)
class EncounterSlot(TableBase):
u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
u"""An abstract "slot" within a method, associated with both some set of conditions and a rarity.
Note that there are two encounters per slot, so the rarities will only add
up to 50.
"""
__tablename__ = 'encounter_slots'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for this slot"))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False,
info=dict(description="The ID of the version group this slot is in"))
encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=False, nullable=False, autoincrement=False,
info=dict(description="The ID of the terrain"))
encounter_method_id = Column(Integer, ForeignKey('encounter_methods.id'), primary_key=False, nullable=False, autoincrement=False,
info=dict(description="The ID of the method"))
slot = Column(Integer, nullable=True,
info=dict(description="This slot's order for the location and terrain"))
rarity = Column(Integer, nullable=False,
info=dict(description="This slot's order for the location and method"))
rarity = Column(Integer, nullable=True,
info=dict(description="The chance of the encounter as a percentage"))
class EncounterTerrain(TableBase):
u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
"""
__tablename__ = 'encounter_terrain'
__singlename__ = __tablename__
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
info=dict(description="A unique ID for the terrain"))
identifier = Column(Unicode(64), nullable=False,
info=dict(description="An identifier", format='identifier'))
create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
name = Column(Unicode(64), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=False)),
)
class EvolutionChain(TableBase):
u"""A family of Pokémon that are linked by evolution
"""
__tablename__ = 'evolution_chains'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), nullable=False,
info=dict(description="ID of the growth rate for this family"))
@ -415,7 +415,7 @@ class EvolutionTrigger(TableBase):
"""
__tablename__ = 'evolution_triggers'
__singlename__ = 'evolution_trigger'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(16), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -429,7 +429,7 @@ class Experience(TableBase):
u"""EXP needed for a certain level with a certain growth rate
"""
__tablename__ = 'experience'
growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), primary_key=True, nullable=False, autoincrement=False,
growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), primary_key=True, nullable=False,
info=dict(description="ID of the growth rate"))
level = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
info=dict(description="The level"))
@ -441,7 +441,7 @@ class Generation(TableBase):
"""
__tablename__ = 'generations'
__singlename__ = 'generation'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
main_region_id = Column(Integer, ForeignKey('regions.id'), nullable=False,
info=dict(description="ID of the region this generation's main games take place in"))
@ -461,7 +461,7 @@ class GrowthRate(TableBase):
"""
__tablename__ = 'growth_rates'
__singlename__ = 'growth_rate'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(20), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -478,7 +478,7 @@ class Item(TableBase):
"""
__tablename__ = 'items'
__singlename__ = 'item'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(20), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -519,7 +519,7 @@ class ItemCategory(TableBase):
# XXX: This is fanon, right?
__tablename__ = 'item_categories'
__singlename__ = 'item_category'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
pocket_id = Column(Integer, ForeignKey('item_pockets.id'), nullable=False,
info=dict(description="ID of the pocket these items go to"))
@ -537,7 +537,7 @@ class ItemFlag(TableBase):
"""
__tablename__ = 'item_flags'
__singlename__ = 'item_flag'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(24), nullable=False,
info=dict(description="Identifier of the flag", format='identifier'))
@ -568,7 +568,7 @@ class ItemFlavorText(TableBase):
info=dict(description="The ID of the item"))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
info=dict(description="ID of the version group that sports this text"))
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
info=dict(description="The language"))
flavor_text = Column(Unicode(255), nullable=False,
info=dict(description="The flavor text itself", official=True, format='gametext'))
@ -578,7 +578,7 @@ class ItemFlingEffect(TableBase):
"""
__tablename__ = 'item_fling_effects'
__singlename__ = 'item_fling_effect'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
create_translation_table('item_fling_effect_prose', ItemFlingEffect, 'prose',
@ -602,7 +602,7 @@ class ItemPocket(TableBase):
"""
__tablename__ = 'item_pockets'
__singlename__ = 'item_pocket'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(16), nullable=False,
info=dict(description="An identifier of this pocket", format='identifier'))
@ -618,7 +618,7 @@ class Location(TableBase):
"""
__tablename__ = 'locations'
__singlename__ = 'location'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
region_id = Column(Integer, ForeignKey('regions.id'),
info=dict(description="ID of the region this location is in"))
@ -636,7 +636,7 @@ class LocationArea(TableBase):
"""
__tablename__ = 'location_areas'
__singlename__ = 'location_area'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
location_id = Column(Integer, ForeignKey('locations.id'), nullable=False,
info=dict(description="ID of the location this area is part of"))
@ -656,8 +656,8 @@ class LocationAreaEncounterRate(TableBase):
__tablename__ = 'location_area_encounter_rates'
location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="ID of the area"))
encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="ID of the terrain"))
encounter_method_id = Column(Integer, ForeignKey('encounter_methods.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="ID of the method"))
version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False,
info=dict(description="ID of the version"))
rate = Column(Integer, nullable=True,
@ -667,11 +667,11 @@ class LocationGameIndex(TableBase):
u"""IDs the games use internally for locations
"""
__tablename__ = 'location_game_indices'
location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True, autoincrement=False,
location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True,
info=dict(description="Database ID of the locaion"))
generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True, autoincrement=False,
generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True,
info=dict(description="ID of the generation this entry to"))
game_index = Column(Integer, nullable=False,
game_index = Column(Integer, nullable=False, primary_key=True, autoincrement=False,
info=dict(description="Internal game ID of the location"))
class Machine(TableBase):
@ -698,7 +698,7 @@ class Move(TableBase):
"""
__tablename__ = 'moves'
__singlename__ = 'move'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(24), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -743,7 +743,7 @@ class MoveBattleStyle(TableBase):
u"""A battle style of a move""" # XXX: Explain better
__tablename__ = 'move_battle_styles'
__singlename__ = 'move_battle_style'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(8), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -758,9 +758,9 @@ class MoveChangelog(TableBase):
"""History of changes to moves across main game versions."""
__tablename__ = 'move_changelog'
__singlename__ = 'move_changelog'
move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
info=dict(description="ID of the move that changed"))
changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
info=dict(description="ID of the version group in which the move changed"))
type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
info=dict(description="Prior type of the move, or NULL if unchanged"))
@ -780,7 +780,7 @@ class MoveDamageClass(TableBase):
"""
__tablename__ = 'move_damage_classes'
__singlename__ = 'move_damage_class'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(16), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -798,7 +798,7 @@ class MoveEffect(TableBase):
"""
__tablename__ = 'move_effects'
__singlename__ = 'move_effect'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
create_translation_table('move_effect_prose', MoveEffect, 'prose',
@ -813,7 +813,7 @@ class MoveEffectCategory(TableBase):
"""
__tablename__ = 'move_effect_categories'
__singlename__ = 'move_effect_category'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(64), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -829,18 +829,18 @@ class MoveEffectCategoryMap(TableBase):
u"""Maps a move effect category to a move effect
"""
__tablename__ = 'move_effect_category_map'
move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False, autoincrement=False,
move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
info=dict(description="ID of the move effect"))
move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False, autoincrement=False,
move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
info=dict(description="ID of the category"))
affects_user = Column(Boolean, primary_key=True, nullable=False, autoincrement=False,
affects_user = Column(Boolean, primary_key=True, nullable=False,
info=dict(description="Set if the user is affected"))
class MoveEffectChangelog(TableBase):
"""History of changes to move effects across main game versions."""
__tablename__ = 'move_effect_changelog'
__singlename__ = 'move_effect_changelog'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
info=dict(description="The ID of the effect that changed"))
@ -873,7 +873,7 @@ class MoveFlagType(TableBase):
"""
__tablename__ = 'move_flag_types'
__singlename__ = 'move_flag_type'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(32), nullable=False,
info=dict(description="A short identifier for the flag", format='identifier'))
@ -895,7 +895,7 @@ class MoveFlavorText(TableBase):
info=dict(description="ID of the move"))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="ID of the version group this text appears in"))
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
info=dict(description="The language"))
flavor_text = Column(Unicode(255), nullable=False,
info=dict(description="The flavor text", official=True, format='gametext'))
@ -951,7 +951,7 @@ class MoveMetaCategory(TableBase):
u"""Very general categories that loosely group move effects."""
__tablename__ = 'move_meta_categories'
__singlename__ = 'move_meta_category'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
@ -975,7 +975,7 @@ class MoveTarget(TableBase):
"""
__tablename__ = 'move_targets'
__singlename__ = 'move_target'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(32), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -993,7 +993,7 @@ class Nature(TableBase):
"""
__tablename__ = 'natures'
__singlename__ = 'nature'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(8), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -1026,9 +1026,9 @@ class NatureBattleStylePreference(TableBase):
a particular battl style in Battle Palace or Battle Tent
"""
__tablename__ = 'nature_battle_style_preferences'
nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False,
nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
info=dict(description=u"ID of the Pokémon's nature"))
move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False, autoincrement=False,
move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False,
info=dict(description="ID of the battle style"))
low_hp_preference = Column(Integer, nullable=False,
info=dict(description=u"Chance of using the move, in percent, if HP is under ½"))
@ -1039,9 +1039,9 @@ class NaturePokeathlonStat(TableBase):
u"""Specifies how a Nature affects a Pokéathlon stat
"""
__tablename__ = 'nature_pokeathlon_stats'
nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False,
nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
info=dict(description="ID of the nature"))
pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False, autoincrement=False,
pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False,
info=dict(description="ID of the stat"))
max_change = Column(Integer, nullable=False,
info=dict(description="Maximum change"))
@ -1051,7 +1051,7 @@ class PokeathlonStat(TableBase):
"""
__tablename__ = 'pokeathlon_stats'
__singlename__ = 'pokeathlon_stat'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(8), nullable=False,
info=dict(description="An identifier", format='identifier'))
@ -1066,7 +1066,7 @@ class Pokedex(TableBase):
"""
__tablename__ = 'pokedexes'
__singlename__ = 'pokedex'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
region_id = Column(Integer, ForeignKey('regions.id'), nullable=True,
info=dict(description=u"ID of the region this Pokédex is used in, or None if it's global"))
@ -1086,7 +1086,7 @@ class Pokemon(TableBase):
"""
__tablename__ = 'pokemon'
__singlename__ = 'pokemon'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A numeric ID"))
identifier = Column(Unicode(20), nullable=False,
info=dict(description=u"An identifier", format='identifier'))
@ -1153,7 +1153,7 @@ class Pokemon(TableBase):
u"""Returns the Pokémon's name, including its form if applicable."""
if self.form_name:
return u'{0} {1}'.format(self.form_name, self.name)
return u'%s %s' % (self.form_name, self.name)
else:
return self.name
@ -1315,7 +1315,7 @@ class PokemonFlavorText(TableBase):
info=dict(description=u"ID of the Pokémon"))
version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description=u"ID of the version that has this flavor text"))
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
info=dict(description="The language"))
flavor_text = Column(Unicode(255), nullable=False,
info=dict(description=u"The flavor text", official=True, format='gametext'))
@ -1328,7 +1328,7 @@ class PokemonForm(TableBase):
"""
__tablename__ = 'pokemon_forms'
__singlename__ = 'pokemon_form'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u'A unique ID for this form.'))
identifier = Column(Unicode(16), nullable=True,
info=dict(description=u"An identifier", format='identifier'))
@ -1357,7 +1357,7 @@ class PokemonForm(TableBase):
if not self.name:
return None
elif self.form_group and self.form_group.term:
return u'{0} {1}'.format(self.name, self.form_group.term)
return u'%s %s' % (self.name, self.form_group.term)
else:
return self.name
@ -1368,7 +1368,7 @@ class PokemonForm(TableBase):
"""
if self.name:
return u'{0} {1}'.format(self.name, self.form_base_pokemon.name)
return u'%s %s' % (self.name, self.form_base_pokemon.name)
else:
return self.form_base_pokemon.name
@ -1495,7 +1495,7 @@ class PokemonShape(TableBase):
"""
__tablename__ = 'pokemon_shapes'
__singlename__ = 'pokemon_shape'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A numeric ID"))
identifier = Column(Unicode(24), nullable=False,
info=dict(description=u"An identifier", format='identifier'))
@ -1537,7 +1537,7 @@ class Region(TableBase):
"""
__tablename__ = 'regions'
__singlename__ = 'region'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A numeric ID"))
identifier = Column(Unicode(16), nullable=False,
info=dict(description=u"An identifier", format='identifier'))
@ -1553,7 +1553,7 @@ class Stat(TableBase):
"""
__tablename__ = 'stats'
__singlename__ = 'stat'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A numeric ID"))
damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
@ -1574,7 +1574,7 @@ class StatHint(TableBase):
"""
__tablename__ = 'stat_hints'
__singlename__ = 'stat_hint'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A numeric ID"))
stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
info=dict(description=u"ID of the highest stat"))
@ -1601,7 +1601,7 @@ class SuperContestEffect(TableBase):
"""
__tablename__ = 'super_contest_effects'
__singlename__ = 'super_contest_effect'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"This effect's unique ID."))
appeal = Column(SmallInteger, nullable=False,
info=dict(description=u"The number of hearts the user gains."))
@ -1615,7 +1615,7 @@ class Type(TableBase):
u"""Any of the elemental types Pokémon and moves can have."""
__tablename__ = 'types'
__singlename__ = 'type'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A unique ID for this type."))
identifier = Column(Unicode(12), nullable=False,
info=dict(description=u"An identifier", format='identifier'))
@ -1646,7 +1646,7 @@ class Version(TableBase):
u"""An individual main-series Pokémon game."""
__tablename__ = 'versions'
__singlename__ = 'version'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A unique ID for this version."))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
info=dict(description=u"The ID of the version group this game belongs to."))
@ -1664,7 +1664,7 @@ class VersionGroup(TableBase):
and Blue) or a single game (such as Yellow.)
"""
__tablename__ = 'version_groups'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"This version group's unique ID."))
generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
info=dict(description=u"The ID of the generation the games in this group belong to."))
@ -1674,9 +1674,9 @@ class VersionGroup(TableBase):
class VersionGroupRegion(TableBase):
u"""Maps a version group to a region that appears in it."""
__tablename__ = 'version_group_regions'
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
info=dict(description=u"The ID of the version group."))
region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False, autoincrement=False,
region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
info=dict(description=u"The ID of the region."))
@ -1747,7 +1747,7 @@ EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
innerjoin=True, lazy='joined',
backref='encounter_map')
EncounterSlot.terrain = relation(EncounterTerrain,
EncounterSlot.method = relation(EncounterMethod,
innerjoin=True, lazy='joined',
backref='slots')
EncounterSlot.version_group = relation(VersionGroup, innerjoin=True)
@ -1824,6 +1824,12 @@ LocationArea.location = relation(Location,
innerjoin=True, lazy='joined',
backref='areas')
LocationAreaEncounterRate.location_area = relation(LocationArea,
innerjoin=True,
backref='encounter_rates')
LocationAreaEncounterRate.method = relation(EncounterMethod,
innerjoin=True)
LocationGameIndex.location = relation(Location,
innerjoin=True, lazy='joined',
backref='game_indices')

View file

@ -1,13 +1,13 @@
""" pokedex.defaults - logic for finding default paths """
import os
import pkg_resources
def get_default_db_uri_with_origin():
uri = os.environ.get('POKEDEX_DB_ENGINE', None)
origin = 'environment'
if uri is None:
import pkg_resources
sqlite_path = pkg_resources.resource_filename('pokedex',
'data/pokedex.sqlite')
uri = 'sqlite:///' + sqlite_path
@ -20,6 +20,7 @@ def get_default_index_dir_with_origin():
origin = 'environment'
if index_dir is None:
import pkg_resources
index_dir = pkg_resources.resource_filename('pokedex',
'data/whoosh-index')
origin = 'default'
@ -27,6 +28,7 @@ def get_default_index_dir_with_origin():
return index_dir, origin
def get_default_csv_dir_with_origin():
import pkg_resources
csv_dir = pkg_resources.resource_filename('pokedex', 'data/csv')
origin = 'default'

292
pokedex/main.py Normal file
View file

@ -0,0 +1,292 @@
# encoding: utf8
from optparse import OptionParser
import os
import sys
import pokedex.db
import pokedex.db.load
import pokedex.db.tables
import pokedex.lookup
from pokedex import defaults
def main():
if len(sys.argv) <= 1:
command_help()
command = sys.argv[1]
args = sys.argv[2:]
# XXX there must be a better way to get Unicode argv
# XXX this doesn't work on Windows durp
enc = sys.stdin.encoding or 'utf8'
args = [_.decode(enc) for _ in args]
# Find the command as a function in this file
func = globals().get("command_%s" % command, None)
if func:
func(*args)
else:
command_help()
def get_parser(verbose=True):
"""Returns an OptionParser prepopulated with the global options.
`verbose` is whether or not the options should be verbose by default.
"""
parser = OptionParser()
parser.add_option('-e', '--engine', dest='engine_uri', default=None)
parser.add_option('-i', '--index', dest='index_dir', default=None)
parser.add_option('-q', '--quiet', dest='verbose', default=verbose, action='store_false')
parser.add_option('-v', '--verbose', dest='verbose', default=verbose, action='store_true')
return parser
def get_session(options):
"""Given a parsed options object, connects to the database and returns a
session.
"""
engine_uri = options.engine_uri
got_from = 'command line'
if engine_uri is None:
engine_uri, got_from = defaults.get_default_db_uri_with_origin()
session = pokedex.db.connect(engine_uri)
if options.verbose:
print "Connected to database %(engine)s (from %(got_from)s)" \
% dict(engine=session.bind.url, got_from=got_from)
return session
def get_lookup(options, session=None, recreate=False):
"""Given a parsed options object, opens the whoosh index and returns a
PokedexLookup object.
"""
if recreate and not session:
raise ValueError("get_lookup() needs an explicit session to regen the index")
index_dir = options.index_dir
got_from = 'command line'
if index_dir is None:
index_dir, got_from = defaults.get_default_index_dir_with_origin()
if options.verbose:
print "Opened lookup index %(index_dir)s (from %(got_from)s)" \
% dict(index_dir=index_dir, got_from=got_from)
lookup = pokedex.lookup.PokedexLookup(index_dir, session=session)
if recreate:
lookup.rebuild_index()
return lookup
def get_csv_directory(options):
"""Prints and returns the csv directory we're about to use."""
if not options.verbose:
return
csvdir = options.directory
got_from = 'command line'
if csvdir is None:
csvdir, got_from = defaults.get_default_csv_dir_with_origin()
print "Using CSV directory %(csvdir)s (from %(got_from)s)" \
% dict(csvdir=csvdir, got_from=got_from)
return csvdir
### Plumbing commands
def command_dump(*args):
parser = get_parser(verbose=True)
parser.add_option('-d', '--directory', dest='directory', default=None)
options, tables = parser.parse_args(list(args))
session = get_session(options)
get_csv_directory(options)
pokedex.db.load.dump(session, directory=options.directory,
tables=tables,
verbose=options.verbose)
def command_load(*args):
parser = get_parser(verbose=True)
parser.add_option('-d', '--directory', dest='directory', default=None)
parser.add_option('-D', '--drop-tables', dest='drop_tables', default=False, action='store_true')
parser.add_option('-r', '--recursive', dest='recursive', default=False, action='store_true')
parser.add_option('-S', '--safe', dest='safe', default=False, action='store_true',
help="Do not use backend-specific optimalizations.")
options, tables = parser.parse_args(list(args))
if not options.engine_uri:
print "WARNING: You're reloading the default database, but not the lookup index. They"
print " might get out of sync, and pokedex commands may not work correctly!"
print "To fix this, run `pokedex reindex` when this command finishes. Or, just use"
print "`pokedex setup` to do both at once."
print
session = get_session(options)
get_csv_directory(options)
pokedex.db.load.load(session, directory=options.directory,
drop_tables=options.drop_tables,
tables=tables,
verbose=options.verbose,
safe=options.safe,
recursive=options.recursive)
def command_reindex(*args):
parser = get_parser(verbose=True)
options, _ = parser.parse_args(list(args))
session = get_session(options)
lookup = get_lookup(options, session=session, recreate=True)
print "Recreated lookup index."
def command_setup(*args):
parser = get_parser(verbose=False)
options, _ = parser.parse_args(list(args))
options.directory = None
session = get_session(options)
get_csv_directory(options)
pokedex.db.load.load(session, directory=None, drop_tables=True,
verbose=options.verbose,
safe=False)
lookup = get_lookup(options, session=session, recreate=True)
print "Recreated lookup index."
def command_status(*args):
parser = get_parser(verbose=True)
options, _ = parser.parse_args(list(args))
options.verbose = True
options.directory = None
# Database, and a lame check for whether it's been inited at least once
session = get_session(options)
print " - OK! Connected successfully."
if pokedex.db.tables.Pokemon.__table__.exists(session.bind):
print " - OK! Database seems to contain some data."
else:
print " - WARNING: Database appears to be empty."
# CSV; simple checks that the dir exists
csvdir = get_csv_directory(options)
if not os.path.exists(csvdir):
print " - ERROR: No such directory!"
elif not os.path.isdir(csvdir):
print " - ERROR: Not a directory!"
else:
print " - OK! Directory exists."
if os.access(csvdir, os.R_OK):
print " - OK! Can read from directory."
else:
print " - ERROR: Can't read from directory!"
if os.access(csvdir, os.W_OK):
print " - OK! Can write to directory."
else:
print " - WARNING: Can't write to directory! " \
"`dump` will not work. You may need to sudo."
# Index; the PokedexLookup constructor covers most tests and will
# cheerfully bomb if they fail
lookup = get_lookup(options, recreate=False)
print " - OK! Opened successfully."
### User-facing commands
def command_lookup(*args):
parser = get_parser(verbose=False)
options, words = parser.parse_args(list(args))
name = u' '.join(words)
session = get_session(options)
lookup = get_lookup(options, session=session, recreate=False)
results = lookup.lookup(name)
if not results:
print "No matches."
elif results[0].exact:
print "Matched:"
else:
print "Fuzzy-matched:"
for result in results:
if hasattr(result.object, 'full_name'):
name = result.object.full_name
else:
name = result.object.name
print "%s: %s" % (result.object.__tablename__, name),
if result.language:
print "(%s in %s)" % (result.name, result.language)
else:
print
def command_help():
print u"""pokedex -- a command-line Pokédex interface
usage: pokedex {command} [options...]
Run `pokedex setup` first, or nothing will work!
See http://bugs.veekun.com/projects/pokedex/wiki/CLI for more documentation.
Commands:
help Displays this message.
lookup [thing] Look up something in the Pokédex.
System commands:
load Load Pokédex data into a database from CSV files.
dump Dump Pokédex data from a database into CSV files.
reindex Rebuilds the lookup index from the database.
setup Combines load and reindex.
status No effect, but prints which engine, index, and csv
directory would be used for other commands.
Global options:
-e|--engine=URI By default, all commands try to use a SQLite database
in the pokedex install directory. Use this option (or
a POKEDEX_DB_ENGINE environment variable) to specify an
alternate database.
-i|--index=DIR By default, all commands try to put the lookup index in
the pokedex install directory. Use this option (or a
POKEDEX_INDEX_DIR environment variable) to specify an
alternate loction.
-q|--quiet Don't print system output. This is the default for
non-system commands and setup.
-v|--verbose Print system output. This is the default for system
commands, except setup.
System options:
-d|--directory=DIR By default, load and dump will use the CSV files in the
pokedex install directory. Use this option to specify
a different directory.
Load options:
-D|--drop-tables Drop all tables before loading data.
-S|--safe Disable engine-specific optimizations.
-r|--recursive Load (and drop) all dependent tables.
Additionally, load and dump accept a list of table names (possibly with
wildcards) and/or csv fileames as an argument list.
""".encode(sys.getdefaultencoding(), 'replace')
sys.exit(0)

View file

@ -145,4 +145,3 @@ except ImportError:
pass
return result

49
scripts/add-bw-locations.py Executable file
View file

@ -0,0 +1,49 @@
#!/usr/bin/env python2
from codecs import open
from pokedex.db import connect, identifier_from_name
from pokedex.db.tables import Language
from pokedex.db.tables import Location, LocationGameIndex
session = connect()
en = session.query(Language).filter_by(identifier='en').one() # English
ja = session.query(Language).filter_by(identifier='ja').one() # Japanese
with open("bw-location-names-en", "r", "utf-8") as f:
en_names = [line.rstrip("\n") for line in f]
with open("bw-location-names-kanji", "r", "utf-8") as f:
ja_names = [line.rstrip("\n") for line in f]
locations = {}
for i, name in enumerate(zip(en_names, ja_names)):
if i == 0:
continue
en_name, ja_name = name
if not en_name:
continue
if name in locations:
loc = locations[name]
else:
loc = Location()
if en_name:
loc.name_map[en] = en_name
if ja_name:
loc.name_map[ja] = ja_name
loc.region_id = 5 # Unova
loc.identifier = identifier_from_name(en_name)
locations[name] = loc
lgi = LocationGameIndex()
lgi.location = loc
lgi.generation_id = 5 # Gen 5
lgi.game_index = i
session.add(loc)
session.add(lgi)
session.commit()

272
scripts/migration-i18n.py Normal file
View file

@ -0,0 +1,272 @@
# Encoding: UTF-8
"""Moves/transforms values in CSVs in an ad-hoc way, based mainly on column name
Auto-creates identifiers from names
Auto-creates names from identifiers
Copies IDs for foreign keys
Creates autoincrement-style IDs when missing
Sets text language to 9 (en), except when it sets to 1 (jp)
And looks good doing it!
"""
import csv
import re
import os
from StringIO import StringIO
from collections import namedtuple, defaultdict
from sqlalchemy.orm import class_mapper
from pokedex.db import tables, load
english_id = 9
japanese_id = 1
bw_version_group_id = 11
dir = load.get_default_csv_dir()
def tuple_key(tup):
"""Return a sort key for mixed int/string tuples.
Strings sort first.
"""
def generator():
for item in tup:
try:
yield (1, int(item))
except ValueError:
yield (0, item)
return tuple(generator())
class MakeFieldFuncs:
"""Various ways to get a new value from the old one"""
@staticmethod
def copy(field_name, source, **kwargs):
"""Plain copy"""
return source[field_name]
@staticmethod
def main(field_name, source, **kwargs):
"""Populate aux table from the main table"""
return source[field_name]
@staticmethod
def Main(field_name, source, **kwargs):
"""Capitalize"""
return source[field_name].capitalize()
@staticmethod
def ident(source, **kwargs):
"""Craft an identifier from the 'identifier' or 'name' column"""
return name2ident(source.get('identifier', source.get('name')))
@staticmethod
def Name(source, **kwargs):
"""Capitalize the name (or identifier) column"""
name = source.get('name', source.get('identifier', None))
name = ' '.join(word.capitalize() for word in name.split(' '))
return name
@staticmethod
def f_id(source, **kwargs):
"""Capitalize the identifier column"""
return source['identifier'].capitalize()
@staticmethod
def name(source, **kwargs):
"""Get the original name"""
return source['name']
@staticmethod
def newid(i, source, **kwargs):
"""Assign a new "auto-incremented" id"""
source['id'] = i # hack to make srcid work
return i
@staticmethod
def en(source, **kwargs):
"""Assign the value for English -- unless it's Japanese"""
if source.get('version_group_id', None) == str(bw_version_group_id):
return japanese_id
return english_id
@staticmethod
def srcid(source, field_name, **kwargs):
"""The original table's id"""
try:
return source['id']
except KeyError:
if field_name == 'pokemon_form_group_id':
# This one reuses another table's ID
return source['pokemon_id']
else:
raise
def name2ident(name):
ident = name.decode('utf-8').lower()
ident = ident.replace(u'+', ' plus ')
ident = re.sub(u'[ _]+', u'-', ident)
ident = re.sub(u'[\'./;(),:]', u'', ident)
ident = ident.replace(u'é', 'e')
ident = ident.replace(u'', '-f')
ident = ident.replace(u'', '-m')
if ident in ('???', '????'):
ident = 'unknown'
elif ident == '!':
ident = 'exclamation'
elif ident == '?':
ident = 'question'
for c in ident:
assert c in "abcdefghijklmnopqrstuvwxyz0123456789-", repr(ident)
return ident
FieldSpec = namedtuple('FieldSpec', 'out name func')
def main():
for table in sorted(tables.all_tables(), key=lambda t: t.__name__):
datafilename = dir + '/' + table.__tablename__ + '.csv'
classname = table.__name__
if hasattr(table, 'object_table'):
# This is an auxilliary table; it'll be processed with the main one
continue
else:
print "%s: %s" % (classname, table.__tablename__)
with open(datafilename) as datafile:
datacsv = csv.reader(datafile, lineterminator='\n')
orig_fields = datacsv.next()
columns = class_mapper(table).c
new_fields = []
main_out = []
outputs = {datafilename: main_out}
name_out = None
srcfiles = [datafilename]
# Set new_fields to a list of FieldSpec object, one for each field we want in the csv
for column in columns:
name = column.name
if name == 'identifier':
new_fields.append(FieldSpec(datafilename, column.name, MakeFieldFuncs.ident))
elif name in orig_fields:
new_fields.append(FieldSpec(datafilename, column.name, MakeFieldFuncs.copy))
elif name == 'id':
new_fields.append(FieldSpec(datafilename, column.name, MakeFieldFuncs.newid))
elif name == 'language_id':
new_fields.insert(2, FieldSpec(datafilename, column.name, MakeFieldFuncs.en))
else:
raise AssertionError(name)
# Remember headers
headers = {datafilename: list(field.name for field in new_fields)}
# Pretty prnt :)
for field in new_fields:
print ' [{0.func.func_name:5}] {0.name}'.format(field)
# Do pretty much the same for aux tables
aux_tables = []
for attrname in 'text_table prose_table'.split():
aux_table = getattr(table, attrname, None)
if aux_table:
aux_datafilename = dir + '/' + aux_table.__tablename__ + '.csv'
print " %s: %s" % (aux_table.__name__, aux_table.__tablename__)
srcfiles.append(datafilename)
aux_tables.append(aux_table)
columns = class_mapper(aux_table).c
aux_out = []
outputs[aux_datafilename] = aux_out
aux_fields = []
for column in columns:
name = column.name
if name == 'language_id':
aux_fields.insert(1, FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.en))
elif name == 'name' and table.__name__ == 'ItemFlag':
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.f_id))
elif name == 'description' and table.__name__ == 'ItemFlag':
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.name))
elif name in orig_fields and name == 'name' and table.__name__ in 'PokemonColor ContestType BerryFirmness'.split():
# Capitalize these names
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.Name))
elif name in orig_fields and name in 'color flavor'.split() and table.__name__ == 'ContestType':
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.Main))
elif name in orig_fields:
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.main))
elif name == table.__singlename__ + '_id':
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.srcid))
elif name == 'name':
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.Name))
elif name == 'lang_id':
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.srcid))
else:
print orig_fields
raise AssertionError(name)
if name == 'name':
# If this table contains the name, remember that
name_fields = aux_fields
name_out = aux_out
# Sort aux tables nicely
def key(f):
if f.func == MakeFieldFuncs.srcid:
return 0
elif f.name == 'language_id':
return 1
elif f.name == 'name':
return 2
else:
return 10
aux_fields.sort(key=key)
new_fields += aux_fields
headers[aux_datafilename] = list(field.name for field in aux_fields)
# Pretty print :)
for field in aux_fields:
print ' [{0.func.func_name:5}] {0.name}'.format(field)
# Do nothing if the table's the same
if all(field.func == MakeFieldFuncs.copy for field in new_fields):
print u' → skipping'
continue
# Otherwise read the file
# outputs will be a (filename -> list of rows) dict
print u' → reading'
for autoincrement_id, src_row in enumerate(datacsv, start=1):
row = dict(zip(orig_fields, src_row))
new_rows = defaultdict(list)
for field in new_fields:
new_rows[field.out].append(field.func(
source=row,
field_name=field.name,
i=autoincrement_id,
))
for name, row in new_rows.items():
outputs[name].append(row)
# If there was a _names table, read that and append it to the
# aux table that has names
try:
name_datafilename = dir + '/' + table.__singlename__ + '_names.csv'
name_file = open(name_datafilename)
except (AttributeError, IOError):
pass
else:
print u' → reading foreign names'
with name_file:
namecsv = csv.reader(name_file, lineterminator='\n')
src_fields = namecsv.next()
obj_id_fieldname = table.__singlename__ + '_id'
assert src_fields == [obj_id_fieldname, 'language_id', 'name']
for name_row in namecsv:
name_dict = dict(zip(src_fields, name_row))
row = []
for field in name_fields:
row.append(name_dict.get(field.name, ''))
name_out.append(row)
os.unlink(name_datafilename)
# For all out files, write a header & sorted rows
print u' → writing'
for filename, rows in outputs.items():
with open(filename, 'w') as outfile:
outcsv = csv.writer(outfile, lineterminator='\n')
outcsv.writerow(headers[filename])
rows.sort(key=tuple_key)
for row in rows:
outcsv.writerow(row)
if __name__ == '__main__':
main()

View file

@ -16,7 +16,7 @@ setup(
entry_points = {
'console_scripts': [
'pokedex = pokedex:main',
'pokedex = pokedex.main:main',
],
},
)