5 Columns have a info dictionary with these keys:
6 - description: The description of the column
7 - official: True if the values appear in games or official material; False if
8 they are fan-created or fan-written. This flag is currently only set for
10 - markup: The format of a text column. Can be one of:
11 - plaintext: Normal Unicode text (widely used in names)
12 - markdown: Veekun's Markdown flavor (generally used in effect descriptions)
13 - gametext: Transcription of in-game text that strives to be both
14 human-readable and represent the original text exactly.
15 - identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
17 - latex: A formula in LaTeX syntax.
19 A localizable text column is visible as two properties:
20 The plural-name property (e.g. Pokemon.names) is a language-to-name dictionary:
21 bulbasaur.names['en'] == "Bulbasaur" and bulbasaur.names['de'] == "Bisasam".
22 You can use Pokemon.names['en'] to filter a query.
23 The singular-name property returns the name in the default language, English.
24 For example bulbasaur.name == "Bulbasaur"
25 Setting pokedex.db.tables.default_lang changes the default language.
27 # XXX: Check if "gametext" is set correctly everywhere
30 from functools
import partial
32 from sqlalchemy
import Column
, ForeignKey
, MetaData
, PrimaryKeyConstraint
, Table
, UniqueConstraint
33 from sqlalchemy
.ext
.declarative
import (
34 declarative_base
, declared_attr
, DeclarativeMeta
,
36 from sqlalchemy
.ext
.associationproxy
import association_proxy
37 from sqlalchemy
.orm
import (
38 backref
, compile_mappers
, eagerload_all
, relation
, class_mapper
, synonym
, mapper
,
40 from sqlalchemy
.orm
.session
import Session
, object_session
41 from sqlalchemy
.orm
.interfaces
import AttributeExtension
42 from sqlalchemy
.orm
.collections
import attribute_mapped_collection
, MappedCollection
, collection
, collection_adapter
43 from sqlalchemy
.ext
.associationproxy
import _AssociationDict
, association_proxy
44 from sqlalchemy
.sql
import and_
45 from sqlalchemy
.sql
.expression
import ColumnOperators
, bindparam
46 from sqlalchemy
.schema
import ColumnDefault
47 from sqlalchemy
.types
import *
48 from inspect
import isclass
50 from pokedex
.db
import markdown
52 # A list of all table classes will live in table_classes
55 class TableMetaclass(DeclarativeMeta
):
56 def __init__(cls
, name
, bases
, attrs
):
57 super(TableMetaclass
, cls
).__init__(name
, bases
, attrs
)
58 if hasattr(cls
, '__tablename__'):
59 table_classes
.append(cls
)
61 class TableSuperclass(object):
62 """Superclass for declarative tables, to give them some generic niceties
65 def __unicode__(self
):
66 """Be as useful as possible. Show the primary key, and an identifier
69 typename
= u
'.'.join((__name__
, type(self
).__name__
))
71 pk_constraint
= self
.__table__
.primary_key
73 return u
"<%s object at %x>" %
(typename
, id(self
))
75 pk
= u
', '.join(unicode(getattr(self
, column
.name
))
76 for column
in pk_constraint
.columns
)
78 return u
"<%s object (%s): %s>" %
(typename
, pk
, self
.identifier
)
79 except AttributeError:
80 return u
"<%s object (%s)>" %
(typename
, pk
)
83 return unicode(self
).encode('utf8')
86 TableBase
= declarative_base(metadata
=metadata
, cls
=TableSuperclass
, metaclass
=TableMetaclass
)
89 class LanguageSpecific(object):
90 """Mixin for prose and text tables"""
93 return Column(Integer
, ForeignKey('languages.id'), primary_key
=True, nullable
=False,
94 info
=dict(description
="The language"))
96 class LanguageSpecificColumn(object):
97 """A column that will not appear in the table it's defined in, but in a related one"""
99 def __init__(self
, *args
, **kwargs
):
101 self
.plural
= kwargs
.pop('plural')
103 self
.order
= self
._ordering
[0]
104 self
._ordering
[0] += 1
106 def makeSAColumn(self
):
107 return Column(*self
.args
, **self
.kwargs
)
109 class ProseColumn(LanguageSpecificColumn
):
110 """A column that will appear in the corresponding _prose table"""
112 class TextColumn(LanguageSpecificColumn
):
113 """A column that will appear in the corresponding _text table"""
116 ### The actual tables
118 class Ability(TableBase
):
119 u
"""An ability a Pokémon can have, such as Static or Pressure.
121 __tablename__
= 'abilities'
122 __singlename__
= 'ability'
123 id = Column(Integer
, primary_key
=True, nullable
=False,
124 info
=dict(description
="This ability's unique ID; matches the games' internal ID"))
125 identifier
= Column(Unicode(24), nullable
=False,
126 info
=dict(description
="An identifier", format
='identifier'))
127 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False,
128 info
=dict(description
="The ID of the generation this ability was introduced in", detail
=True))
129 effect
= ProseColumn(markdown
.MarkdownColumn(5120), plural
='effects', nullable
=False,
130 info
=dict(description
="A detailed description of this ability's effect", format
='markdown'))
131 short_effect
= ProseColumn(markdown
.MarkdownColumn(255), plural
='short_effects', nullable
=False,
132 info
=dict(description
="A short summary of this ability's effect", format
='markdown'))
133 name
= TextColumn(Unicode(24), nullable
=False, index
=True, plural
='names',
134 info
=dict(description
="The name", format
='plaintext', official
=True))
136 class AbilityChangelog(TableBase
):
137 """History of changes to abilities across main game versions."""
138 __tablename__
= 'ability_changelog'
139 __singlename__
= 'ability_changelog'
140 id = Column(Integer
, primary_key
=True, nullable
=False,
141 info
=dict(description
="This change's unique ID"))
142 ability_id
= Column(Integer
, ForeignKey('abilities.id'), nullable
=False,
143 info
=dict(description
="The ID of the ability that changed"))
144 changed_in_version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False,
145 info
=dict(description
="The ID of the version group in which the ability changed"))
146 effect
= ProseColumn(markdown
.MarkdownColumn(255), plural
='effects', nullable
=False,
147 info
=dict(description
="A description of the old behavior", format
='markdown'))
149 class AbilityFlavorText(TableBase
, LanguageSpecific
):
150 u
"""In-game flavor text of an ability
152 __tablename__
= 'ability_flavor_text'
153 ability_id
= Column(Integer
, ForeignKey('abilities.id'), primary_key
=True, nullable
=False, autoincrement
=False,
154 info
=dict(description
="The ID of the ability"))
155 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False,
156 info
=dict(description
="The ID of the version group this flavor text is taken from"))
157 flavor_text
= Column(Unicode(64), nullable
=False,
158 info
=dict(description
="The actual flavor text", official
=True, format
='gametext'))
160 class Berry(TableBase
):
161 u
"""A Berry, consumable item that grows on trees
163 For data common to all items, such as the name, see the corresponding item entry.
165 __tablename__
= 'berries'
166 id = Column(Integer
, primary_key
=True, nullable
=False,
167 info
=dict(description
="This Berry's in-game number"))
168 item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=False,
169 info
=dict(description
="The ID of the item that represents this Berry"))
170 firmness_id
= Column(Integer
, ForeignKey('berry_firmness.id'), nullable
=False,
171 info
=dict(description
="The ID of this Berry's firmness category"))
172 natural_gift_power
= Column(Integer
, nullable
=True,
173 info
=dict(description
="Natural Gift's power when used with this Berry"))
174 natural_gift_type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=True,
175 info
=dict(description
="The ID of the Type that Natural Gift has when used with this Berry"))
176 size
= Column(Integer
, nullable
=False,
177 info
=dict(description
=u
"The size of this Berry, in millimeters"))
178 max_harvest
= Column(Integer
, nullable
=False,
179 info
=dict(description
="The maximum number of these berries that can grow on one tree in Generation IV"))
180 growth_time
= Column(Integer
, nullable
=False,
181 info
=dict(description
="Time it takes the tree to grow one stage, in hours. Berry trees go through four of these growth stages before they can be picked."))
182 soil_dryness
= Column(Integer
, nullable
=False,
183 info
=dict(description
="The speed at which this Berry dries out the soil as it grows. A higher rate means the soil dries more quickly."))
184 smoothness
= Column(Integer
, nullable
=False,
185 info
=dict(description
="The smoothness of this Berry, used in making Pokéblocks or Poffins"))
187 class BerryFirmness(TableBase
):
188 u
"""A Berry firmness, such as "hard" or "very soft".
190 __tablename__
= 'berry_firmness'
191 __singlename__
= 'berry_firmness'
192 id = Column(Integer
, primary_key
=True, nullable
=False,
193 info
=dict(description
="A unique ID for this firmness"))
194 identifier
= Column(Unicode(10), nullable
=False,
195 info
=dict(description
="An identifier", format
='identifier'))
196 name
= TextColumn(Unicode(10), nullable
=False, index
=True, plural
='names',
197 info
=dict(description
="The name", format
='plaintext', official
=True))
199 class BerryFlavor(TableBase
):
200 u
"""A Berry flavor level.
202 __tablename__
= 'berry_flavors'
203 berry_id
= Column(Integer
, ForeignKey('berries.id'), primary_key
=True, nullable
=False, autoincrement
=False,
204 info
=dict(description
="The ID of the berry"))
205 contest_type_id
= Column(Integer
, ForeignKey('contest_types.id'), primary_key
=True, nullable
=False, autoincrement
=False,
206 info
=dict(description
="The ID of the flavor"))
207 flavor
= Column(Integer
, nullable
=False,
208 info
=dict(description
="The level of the flavor in the berry"))
210 class ContestCombo(TableBase
):
211 u
"""Combo of two moves in a Contest.
213 __tablename__
= 'contest_combos'
214 first_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
215 info
=dict(description
="The ID of the first move in the combo"))
216 second_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
217 info
=dict(description
="The ID of the second and final move in the combo"))
219 class ContestEffect(TableBase
):
220 u
"""Effect of a move when used in a Contest.
222 __tablename__
= 'contest_effects'
223 __singlename__
= 'contest_effect'
224 id = Column(Integer
, primary_key
=True, nullable
=False,
225 info
=dict(description
="A unique ID for this effect"))
226 appeal
= Column(SmallInteger
, nullable
=False,
227 info
=dict(description
="The base number of hearts the user of this move gets"))
228 jam
= Column(SmallInteger
, nullable
=False,
229 info
=dict(description
="The base number of hearts the user's opponent loses"))
230 flavor_text
= ProseColumn(Unicode(64), plural
='flavor_texts', nullable
=False,
231 info
=dict(description
="The in-game description of this effect", official
=True, format
='gametext'))
232 effect
= ProseColumn(Unicode(255), plural
='effects', nullable
=False,
233 info
=dict(description
="A detailed description of the effect", format
='plaintext'))
235 class ContestType(TableBase
):
236 u
"""A Contest type, such as "cool" or "smart", and their associated Berry flavors and Pokéblock colors.
238 __tablename__
= 'contest_types'
239 __singlename__
= 'contest_type'
240 id = Column(Integer
, primary_key
=True, nullable
=False,
241 info
=dict(description
="A unique ID for this Contest type"))
242 identifier
= Column(Unicode(6), nullable
=False,
243 info
=dict(description
="An identifier", format
='identifier'))
244 flavor
= TextColumn(Unicode(6), nullable
=False, plural
='flavors',
245 info
=dict(description
="The name of the corresponding Berry flavor", official
=True, format
='plaintext'))
246 color
= TextColumn(Unicode(6), nullable
=False, plural
='colors',
247 info
=dict(description
=u
"The name of the corresponding Pokéblock color", official
=True, format
='plaintext'))
248 name
= TextColumn(Unicode(6), nullable
=False, index
=True, plural
='names',
249 info
=dict(description
="The name", format
='plaintext', official
=True))
251 class EggGroup(TableBase
):
252 u
"""An Egg group. Usually, two Pokémon can breed if they share an Egg Group.
254 (exceptions are the Ditto and No Eggs groups)
256 __tablename__
= 'egg_groups'
257 __singlename__
= 'egg_group'
258 id = Column(Integer
, primary_key
=True, nullable
=False,
259 info
=dict(description
="A unique ID for this group"))
260 identifier
= Column(Unicode(16), nullable
=False,
261 info
=dict(description
=u
"An identifier.", format
='identifier'))
262 name
= ProseColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
263 info
=dict(description
="The name", format
='plaintext', official
=False))
265 class Encounter(TableBase
):
266 u
"""Encounters with wild Pokémon.
270 Within a given area in a given game, encounters are differentiated by the
271 "slot" they are in and the state of the game world.
273 What the player is doing to get an encounter, such as surfing or walking
274 through tall grass, is called terrain. Each terrain has its own set of
277 Within a terrain, slots are defined primarily by rarity. Each slot can
278 also be affected by world conditions; for example, the 20% slot for walking
279 in tall grass is affected by whether a swarm is in effect in that area.
280 "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
281 swarm" are the possible values of this condition.
283 A slot (20% walking in grass) and any appropriate world conditions (no
284 swarm) are thus enough to define a specific encounter.
286 Well, okay, almost: each slot actually appears twice.
289 __tablename__
= 'encounters'
290 id = Column(Integer
, primary_key
=True, nullable
=False,
291 info
=dict(description
="A unique ID for this encounter"))
292 version_id
= Column(Integer
, ForeignKey('versions.id'), nullable
=False, autoincrement
=False,
293 info
=dict(description
="The ID of the version this applies to"))
294 location_area_id
= Column(Integer
, ForeignKey('location_areas.id'), nullable
=False, autoincrement
=False,
295 info
=dict(description
="The ID of the location of this encounter"))
296 encounter_slot_id
= Column(Integer
, ForeignKey('encounter_slots.id'), nullable
=False, autoincrement
=False,
297 info
=dict(description
="The ID of the encounter slot, which determines terrain and rarity"))
298 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=False, autoincrement
=False,
299 info
=dict(description
=u
"The ID of the encountered Pokémon"))
300 min_level
= Column(Integer
, nullable
=False, autoincrement
=False,
301 info
=dict(description
=u
"The minimum level of the encountered Pokémon"))
302 max_level
= Column(Integer
, nullable
=False, autoincrement
=False,
303 info
=dict(description
=u
"The maxmum level of the encountered Pokémon"))
305 class EncounterCondition(TableBase
):
306 u
"""A conditions in the game world that affects Pokémon encounters, such as time of day.
309 __tablename__
= 'encounter_conditions'
310 __singlename__
= 'encounter_condition'
311 id = Column(Integer
, primary_key
=True, nullable
=False,
312 info
=dict(description
="A unique ID for this condition"))
313 identifier
= Column(Unicode(64), nullable
=False,
314 info
=dict(description
="An identifier", format
='identifier'))
315 name
= ProseColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
316 info
=dict(description
="The name", format
='plaintext', official
=False))
318 class EncounterConditionValue(TableBase
):
319 u
"""A possible state for a condition; for example, the state of 'swarm' could be 'swarm' or 'no swarm'.
322 __tablename__
= 'encounter_condition_values'
323 __singlename__
= 'encounter_condition_value'
324 id = Column(Integer
, primary_key
=True, nullable
=False,
325 info
=dict(description
="A numeric ID"))
326 encounter_condition_id
= Column(Integer
, ForeignKey('encounter_conditions.id'), primary_key
=False, nullable
=False, autoincrement
=False,
327 info
=dict(description
="The ID of the encounter condition this is a value of"))
328 identifier
= Column(Unicode(64), nullable
=False,
329 info
=dict(description
="An identifier", format
='identifier'))
330 is_default
= Column(Boolean
, nullable
=False,
331 info
=dict(description
='Set if this value is the default state for the condition'))
332 name
= ProseColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
333 info
=dict(description
="The name", format
='plaintext', official
=False))
335 class EncounterConditionValueMap(TableBase
):
336 u
"""Maps encounters to the specific conditions under which they occur.
338 __tablename__
= 'encounter_condition_value_map'
339 encounter_id
= Column(Integer
, ForeignKey('encounters.id'), primary_key
=True, nullable
=False, autoincrement
=False,
340 info
=dict(description
="The ID of the encounter"))
341 encounter_condition_value_id
= Column(Integer
, ForeignKey('encounter_condition_values.id'), primary_key
=True, nullable
=False, autoincrement
=False,
342 info
=dict(description
="The ID of the encounter condition value"))
344 class EncounterTerrain(TableBase
):
345 u
"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
348 __tablename__
= 'encounter_terrain'
349 __singlename__
= __tablename__
350 id = Column(Integer
, primary_key
=True, nullable
=False,
351 info
=dict(description
="A unique ID for the terrain"))
352 identifier
= Column(Unicode(64), nullable
=False,
353 info
=dict(description
="An identifier", format
='identifier'))
354 name
= ProseColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
355 info
=dict(description
="The name", format
='plaintext', official
=False))
357 class EncounterSlot(TableBase
):
358 u
"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
360 Note that there are two encounters per slot, so the rarities will only add
364 __tablename__
= 'encounter_slots'
365 id = Column(Integer
, primary_key
=True, nullable
=False,
366 info
=dict(description
="A unique ID for this slot"))
367 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False, autoincrement
=False,
368 info
=dict(description
="The ID of the version group this slot is in"))
369 encounter_terrain_id
= Column(Integer
, ForeignKey('encounter_terrain.id'), primary_key
=False, nullable
=False, autoincrement
=False,
370 info
=dict(description
="The ID of the terrain"))
371 slot
= Column(Integer
, nullable
=True,
372 info
=dict(description
="This slot's order for the location and terrain"))
373 rarity
= Column(Integer
, nullable
=False,
374 info
=dict(description
="The chance of the encounter as a percentage"))
376 class EvolutionChain(TableBase
):
377 u
"""A family of Pokémon that are linked by evolution
379 __tablename__
= 'evolution_chains'
380 id = Column(Integer
, primary_key
=True, nullable
=False,
381 info
=dict(description
="A numeric ID"))
382 growth_rate_id
= Column(Integer
, ForeignKey('growth_rates.id'), nullable
=False,
383 info
=dict(description
="ID of the growth rate for this family"))
384 baby_trigger_item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=True,
385 info
=dict(description
="Item that a parent must hold while breeding to produce a baby"))
387 class EvolutionTrigger(TableBase
):
388 u
"""An evolution type, such as "level" or "trade".
390 __tablename__
= 'evolution_triggers'
391 __singlename__
= 'evolution_trigger'
392 id = Column(Integer
, primary_key
=True, nullable
=False,
393 info
=dict(description
="A numeric ID"))
394 identifier
= Column(Unicode(16), nullable
=False,
395 info
=dict(description
="An identifier", format
='identifier'))
396 name
= ProseColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
397 info
=dict(description
="The name", format
='plaintext', official
=False))
399 class Experience(TableBase
):
400 u
"""EXP needed for a certain level with a certain growth rate
402 __tablename__
= 'experience'
403 growth_rate_id
= Column(Integer
, ForeignKey('growth_rates.id'), primary_key
=True, nullable
=False,
404 info
=dict(description
="ID of the growth rate"))
405 level
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
406 info
=dict(description
="The level"))
407 experience
= Column(Integer
, nullable
=False,
408 info
=dict(description
="The number of EXP points needed to get to that level"))
410 class Generation(TableBase
):
411 u
"""A Generation of the Pokémon franchise
413 __tablename__
= 'generations'
414 __singlename__
= 'generation'
415 id = Column(Integer
, primary_key
=True, nullable
=False,
416 info
=dict(description
="A numeric ID"))
417 main_region_id
= Column(Integer
, ForeignKey('regions.id'),
418 info
=dict(description
="ID of the region this generation's main games take place in"))
419 canonical_pokedex_id
= Column(Integer
, ForeignKey('pokedexes.id'),
420 info
=dict(description
=u
"ID of the Pokédex this generation's main games use by default"))
421 identifier
= Column(Unicode(16), nullable
=False,
422 info
=dict(description
=u
'An identifier', format
='identifier'))
423 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
424 info
=dict(description
="The name", format
='plaintext', official
=True))
426 class GrowthRate(TableBase
):
427 u
"""Growth rate of a Pokémon, i.e. the EXP → level function.
429 __tablename__
= 'growth_rates'
430 __singlename__
= 'growth_rate'
431 id = Column(Integer
, primary_key
=True, nullable
=False,
432 info
=dict(description
="A numeric ID"))
433 identifier
= Column(Unicode(20), nullable
=False,
434 info
=dict(description
="An identifier", format
='identifier'))
435 formula
= Column(Unicode(500), nullable
=False,
436 info
=dict(description
="The formula", format
='latex'))
437 name
= ProseColumn(Unicode(20), nullable
=False, index
=True, plural
='names',
438 info
=dict(description
="The name", format
='plaintext', official
=False))
440 class Item(TableBase
):
441 u
"""An Item from the games, like "Poké Ball" or "Bicycle".
443 __tablename__
= 'items'
444 __singlename__
= 'item'
445 id = Column(Integer
, primary_key
=True, nullable
=False,
446 info
=dict(description
="A numeric ID"))
447 identifier
= Column(Unicode(20), nullable
=False,
448 info
=dict(description
="An identifier", format
='identifier'))
449 category_id
= Column(Integer
, ForeignKey('item_categories.id'), nullable
=False,
450 info
=dict(description
="ID of a category this item belongs to"))
451 cost
= Column(Integer
, nullable
=False,
452 info
=dict(description
=u
"Cost of the item when bought. Items sell for half this price."))
453 fling_power
= Column(Integer
, nullable
=True,
454 info
=dict(description
=u
"Power of the move Fling when used with this item."))
455 fling_effect_id
= Column(Integer
, ForeignKey('item_fling_effects.id'), nullable
=True,
456 info
=dict(description
=u
"ID of the fling-effect of the move Fling when used with this item. Note that these are different from move effects."))
457 short_effect
= ProseColumn(Unicode(256), plural
='short_effects', nullable
=False,
458 info
=dict(description
="A short summary of the effect", format
='plaintext'))
459 effect
= ProseColumn(markdown
.MarkdownColumn(5120), plural
='effects', nullable
=False,
460 info
=dict(description
=u
"Detailed description of the item's effect.", format
='markdown'))
461 name
= TextColumn(Unicode(20), nullable
=False, index
=True, plural
='names',
462 info
=dict(description
="The name", format
='plaintext', official
=True))
465 def appears_underground(self
):
466 u
"""True if the item appears underground, as specified by the appropriate flag
468 return any(flag
.identifier
== u
'underground' for flag
in self
.flags
)
470 class ItemCategory(TableBase
):
473 # XXX: This is fanon, right?
474 __tablename__
= 'item_categories'
475 __singlename__
= 'item_category'
476 id = Column(Integer
, primary_key
=True, nullable
=False,
477 info
=dict(description
="A numeric ID"))
478 pocket_id
= Column(Integer
, ForeignKey('item_pockets.id'), nullable
=False,
479 info
=dict(description
="ID of the pocket these items go to"))
480 identifier
= Column(Unicode(16), nullable
=False,
481 info
=dict(description
="An identifier", format
='identifier'))
482 name
= ProseColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
483 info
=dict(description
="The name", format
='plaintext', official
=False))
485 class ItemFlag(TableBase
):
486 u
"""An item attribute such as "consumable" or "holdable".
488 __tablename__
= 'item_flags'
489 __singlename__
= 'item_flag'
490 id = Column(Integer
, primary_key
=True, nullable
=False,
491 info
=dict(description
="A numeric ID"))
492 identifier
= Column(Unicode(24), nullable
=False,
493 info
=dict(description
="Identifier of the flag", format
='identifier'))
494 description
= ProseColumn(Unicode(64), plural
='descriptions', nullable
=False,
495 info
=dict(description
="Short description of the flag", format
='plaintext'))
496 name
= ProseColumn(Unicode(24), nullable
=False, index
=True, plural
='names',
497 info
=dict(description
="The name", format
='plaintext', official
=False))
499 class ItemFlagMap(TableBase
):
500 u
"""Maps an item flag to its item.
502 __tablename__
= 'item_flag_map'
503 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, autoincrement
=False, nullable
=False,
504 info
=dict(description
="The ID of the item"))
505 item_flag_id
= Column(Integer
, ForeignKey('item_flags.id'), primary_key
=True, autoincrement
=False, nullable
=False,
506 info
=dict(description
="The ID of the item flag"))
508 class ItemFlavorText(TableBase
, LanguageSpecific
):
509 u
"""An in-game description of an item
511 __tablename__
= 'item_flavor_text'
512 __singlename__
= 'item_flavor_text'
513 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, autoincrement
=False, nullable
=False,
514 info
=dict(description
="The ID of the item"))
515 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, autoincrement
=False, nullable
=False,
516 info
=dict(description
="ID of the version group that sports this text"))
517 flavor_text
= Column(Unicode(255), nullable
=False,
518 info
=dict(description
="The flavor text itself", official
=True, format
='gametext'))
520 class ItemFlingEffect(TableBase
):
521 u
"""An effect of the move Fling when used with a specific item
523 __tablename__
= 'item_fling_effects'
524 __singlename__
= 'item_fling_effect'
525 id = Column(Integer
, primary_key
=True, nullable
=False,
526 info
=dict(description
="A numeric ID"))
527 effect
= ProseColumn(Unicode(255), plural
='effects', nullable
=False,
528 info
=dict(description
="Description of the effect", format
='plaintext'))
530 class ItemInternalID(TableBase
):
531 u
"""The internal ID number a game uses for an item
533 __tablename__
= 'item_internal_ids'
534 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, autoincrement
=False, nullable
=False,
535 info
=dict(description
="The database ID of the item"))
536 generation_id
= Column(Integer
, ForeignKey('generations.id'), primary_key
=True, autoincrement
=False, nullable
=False,
537 info
=dict(description
="ID of the generation of games"))
538 internal_id
= Column(Integer
, nullable
=False,
539 info
=dict(description
="Internal ID of the item in the generation"))
541 class ItemPocket(TableBase
):
542 u
"""A pocket that categorizes items
544 __tablename__
= 'item_pockets'
545 __singlename__
= 'item_pocket'
546 id = Column(Integer
, primary_key
=True, nullable
=False,
547 info
=dict(description
="A numeric ID"))
548 identifier
= Column(Unicode(16), nullable
=False,
549 info
=dict(description
="An identifier of this pocket", format
='identifier'))
550 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
551 info
=dict(description
="The name", format
='plaintext', official
=True))
553 class Language(TableBase
):
554 u
"""A language the Pokémon games have been transleted into
556 __tablename__
= 'languages'
557 __singlename__
= 'language'
558 id = Column(Integer
, primary_key
=True, nullable
=False,
559 info
=dict(description
="A numeric ID"))
560 iso639
= Column(Unicode(2), nullable
=False,
561 info
=dict(description
="The two-letter code of the country where this language is spoken. Note that it is not unique.", format
='identifier'))
562 iso3166
= Column(Unicode(2), nullable
=False,
563 info
=dict(description
="The two-letter code of the language. Note that it is not unique.", format
='identifier'))
564 identifier
= Column(Unicode(16), nullable
=False,
565 info
=dict(description
="An identifier", format
='identifier'))
566 official
= Column(Boolean
, nullable
=False, index
=True,
567 info
=dict(description
=u
"True iff games are produced in the language."))
568 order
= Column(Integer
, nullable
=True,
569 info
=dict(description
=u
"Order for sorting in foreign name lists."))
570 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
571 info
=dict(description
="The name", format
='plaintext', official
=True))
573 # Languages compare equal to its identifier, so a dictionary of
574 # translations, with a Language as the key, can be indexed by the identifier
575 def __eq__(self
, other
):
579 self
.identifier
== other
or
580 self
.identifier
== other
.identifier
582 except AttributeError:
583 return NotImplemented
585 def __ne__(self
, other
):
586 return not (self
== other
)
589 return hash(self
.identifier
)
591 class Location(TableBase
):
592 u
"""A place in the Pokémon world
594 __tablename__
= 'locations'
595 __singlename__
= 'location'
596 id = Column(Integer
, primary_key
=True, nullable
=False,
597 info
=dict(description
="A numeric ID"))
598 region_id
= Column(Integer
, ForeignKey('regions.id'),
599 info
=dict(description
="ID of the region this location is in"))
600 identifier
= Column(Unicode(64), nullable
=False,
601 info
=dict(description
="An identifier", format
='identifier'))
602 name
= TextColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
603 info
=dict(description
="The name", format
='plaintext', official
=True))
605 class LocationArea(TableBase
):
606 u
"""A sub-area of a location
608 __tablename__
= 'location_areas'
609 __singlename__
= 'location_area'
610 id = Column(Integer
, primary_key
=True, nullable
=False,
611 info
=dict(description
="A numeric ID"))
612 location_id
= Column(Integer
, ForeignKey('locations.id'), nullable
=False,
613 info
=dict(description
="ID of the location this area is part of"))
614 internal_id
= Column(Integer
, nullable
=False,
615 info
=dict(description
="ID the games ude for this area"))
616 identifier
= Column(Unicode(64), nullable
=True,
617 info
=dict(description
="An identifier", format
='identifier'))
618 name
= ProseColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
619 info
=dict(description
="The name", format
='plaintext', official
=False))
621 class LocationAreaEncounterRate(TableBase
):
622 # XXX: What's this exactly? Someone add the docstring & revise the descriptions
623 __tablename__
= 'location_area_encounter_rates'
624 location_area_id
= Column(Integer
, ForeignKey('location_areas.id'), primary_key
=True, nullable
=False, autoincrement
=False,
625 info
=dict(description
="ID of the area"))
626 encounter_terrain_id
= Column(Integer
, ForeignKey('encounter_terrain.id'), primary_key
=True, nullable
=False, autoincrement
=False,
627 info
=dict(description
="ID of the terrain"))
628 version_id
= Column(Integer
, ForeignKey('versions.id'), primary_key
=True, autoincrement
=False,
629 info
=dict(description
="ID of the version"))
630 rate
= Column(Integer
, nullable
=True,
631 info
=dict(description
="The encounter rate")) # units?
633 class LocationInternalID(TableBase
):
634 u
"""IDs the games use internally for locations
636 __tablename__
= 'location_internal_ids'
637 location_id
= Column(Integer
, ForeignKey('locations.id'), nullable
=False, primary_key
=True,
638 info
=dict(description
="Database ID of the locaion"))
639 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False, primary_key
=True,
640 info
=dict(description
="ID of the generation this entry to"))
641 internal_id
= Column(Integer
, nullable
=False,
642 info
=dict(description
="Internal game ID of the location"))
644 class Machine(TableBase
):
645 u
"""A TM or HM; numbered item that can teach a move to a Pokémon
647 __tablename__
= 'machines'
648 machine_number
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
649 info
=dict(description
="Number of the machine for TMs, or 100 + the munber for HMs"))
650 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False,
651 info
=dict(description
="Versions this entry applies to"))
652 item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=False,
653 info
=dict(description
="ID of the corresponding Item"))
654 move_id
= Column(Integer
, ForeignKey('moves.id'), nullable
=False,
655 info
=dict(description
="ID of the taught move"))
659 u
"""True if this machine is a HM, False if it's a TM
661 return self
.machine_number
>= 100
663 class MoveBattleStyle(TableBase
):
664 u
"""A battle style of a move""" # XXX: Explain better
665 __tablename__
= 'move_battle_styles'
666 __singlename__
= 'move_battle_style'
667 id = Column(Integer
, primary_key
=True, nullable
=False,
668 info
=dict(description
="A numeric ID"))
669 identifier
= Column(Unicode(8), nullable
=False,
670 info
=dict(description
="An identifier", format
='identifier'))
671 name
= ProseColumn(Unicode(8), nullable
=False, index
=True, plural
='names',
672 info
=dict(description
="The name", format
='plaintext', official
=False))
674 class MoveEffectCategory(TableBase
):
675 u
"""Category of a move effect
677 __tablename__
= 'move_effect_categories'
678 __singlename__
= 'move_effect_category'
679 id = Column(Integer
, primary_key
=True, nullable
=False,
680 info
=dict(description
="A numeric ID"))
681 identifier
= Column(Unicode(64), nullable
=False,
682 info
=dict(description
="An identifier", format
='identifier'))
683 can_affect_user
= Column(Boolean
, nullable
=False,
684 info
=dict(description
="Set if the user can be affected"))
685 name
= ProseColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
686 info
=dict(description
="The name", format
='plaintext', official
=False))
688 class MoveEffectCategoryMap(TableBase
):
689 u
"""Maps a move effect category to a move effect
691 __tablename__
= 'move_effect_category_map'
692 move_effect_id
= Column(Integer
, ForeignKey('move_effects.id'), primary_key
=True, nullable
=False,
693 info
=dict(description
="ID of the move effect"))
694 move_effect_category_id
= Column(Integer
, ForeignKey('move_effect_categories.id'), primary_key
=True, nullable
=False,
695 info
=dict(description
="ID of the category"))
696 affects_user
= Column(Boolean
, primary_key
=True, nullable
=False,
697 info
=dict(description
="Set if the user is affected"))
699 class MoveDamageClass(TableBase
):
700 u
"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging.
702 __tablename__
= 'move_damage_classes'
703 __singlename__
= 'move_damage_class'
704 id = Column(Integer
, primary_key
=True, nullable
=False,
705 info
=dict(description
="A numeric ID"))
706 identifier
= Column(Unicode(16), nullable
=False,
707 info
=dict(description
="An identifier", format
='identifier'))
708 description
= ProseColumn(Unicode(64), plural
='descriptions', nullable
=False,
709 info
=dict(description
="A description of the class", format
='plaintext'))
710 name
= ProseColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
711 info
=dict(description
="The name", format
='plaintext', official
=False))
713 class MoveEffect(TableBase
):
714 u
"""An effect of a move
716 __tablename__
= 'move_effects'
717 __singlename__
= 'move_effect'
718 id = Column(Integer
, primary_key
=True, nullable
=False,
719 info
=dict(description
="A numeric ID"))
720 short_effect
= ProseColumn(Unicode(256), plural
='short_effects', nullable
=False,
721 info
=dict(description
="A short summary of the effect", format
='plaintext'))
722 effect
= ProseColumn(Unicode(5120), plural
='effects', nullable
=False,
723 info
=dict(description
="A detailed description of the effect", format
='plaintext'))
725 class MoveEffectChangelog(TableBase
):
726 """History of changes to move effects across main game versions."""
727 __tablename__
= 'move_effect_changelog'
728 __singlename__
= 'move_effect_changelog'
729 id = Column(Integer
, primary_key
=True, nullable
=False,
730 info
=dict(description
="A numeric ID"))
731 effect_id
= Column(Integer
, ForeignKey('move_effects.id'), nullable
=False,
732 info
=dict(description
="The ID of the effect that changed"))
733 changed_in_version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False,
734 info
=dict(description
="The ID of the version group in which the effect changed"))
735 effect
= ProseColumn(markdown
.MarkdownColumn(512), plural
='effects', nullable
=False,
736 info
=dict(description
="A description of the old behavior", format
='markdown'))
739 UniqueConstraint(effect_id
, changed_in_version_group_id
),
743 class MoveFlag(TableBase
):
744 u
"""Maps a move flag to a move
746 # XXX: Other flags have a ___Flag class for the actual flag and ___FlagMap for the map,
747 # these, somewhat confusingly, have MoveFlagType and MoveFlag
748 __tablename__
= 'move_flags'
749 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
750 info
=dict(description
="ID of the move"))
751 move_flag_type_id
= Column(Integer
, ForeignKey('move_flag_types.id'), primary_key
=True, nullable
=False, autoincrement
=False,
752 info
=dict(description
="ID of the flag"))
754 class MoveFlagType(TableBase
):
755 u
"""A Move attribute such as "snatchable" or "contact".
757 __tablename__
= 'move_flag_types'
758 __singlename__
= 'move_flag_type'
759 id = Column(Integer
, primary_key
=True, nullable
=False,
760 info
=dict(description
="A numeric ID"))
761 identifier
= Column(Unicode(32), nullable
=False,
762 info
=dict(description
="A short identifier for the flag", format
='identifier'))
763 description
= ProseColumn(markdown
.MarkdownColumn(128), plural
='descriptions', nullable
=False,
764 info
=dict(description
="A short description of the flag", format
='markdown'))
765 name
= ProseColumn(Unicode(32), nullable
=False, index
=True, plural
='names',
766 info
=dict(description
="The name", format
='plaintext', official
=False))
768 class MoveFlavorText(TableBase
, LanguageSpecific
):
769 u
"""In-game description of a move
771 __tablename__
= 'move_flavor_text'
772 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
773 info
=dict(description
="ID of the move"))
774 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False,
775 info
=dict(description
="ID of the version group this text appears in"))
776 flavor_text
= Column(Unicode(255), nullable
=False,
777 info
=dict(description
="The flavor text", official
=True, format
='gametext'))
779 class MoveMeta(TableBase
):
780 u
"""Metadata for move effects, sorta-kinda ripped straight from the game"""
781 __tablename__
= 'move_meta'
782 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
783 info
=dict(description
="A numeric ID"))
784 meta_category_id
= Column(Integer
, ForeignKey('move_meta_categories.id'), nullable
=False,
785 info
=dict(description
="ID of the move category"))
786 meta_ailment_id
= Column(Integer
, ForeignKey('move_meta_ailments.id'), nullable
=False,
787 info
=dict(description
="ID of the caused ailment"))
788 min_hits
= Column(Integer
, nullable
=True, index
=True,
789 info
=dict(description
="Minimum number of hits per use"))
790 max_hits
= Column(Integer
, nullable
=True, index
=True,
791 info
=dict(description
="Maximum number of hits per use"))
792 min_turns
= Column(Integer
, nullable
=True, index
=True,
793 info
=dict(description
="Minimum number of turns the user is forced to use the move"))
794 max_turns
= Column(Integer
, nullable
=True, index
=True,
795 info
=dict(description
="Maximum number of turns the user is forced to use the move"))
796 recoil
= Column(Integer
, nullable
=False, index
=True,
797 info
=dict(description
="Recoil damage, in percent of damage done"))
798 healing
= Column(Integer
, nullable
=False, index
=True,
799 info
=dict(description
="Healing, in percent of user's max HP"))
800 crit_rate
= Column(Integer
, nullable
=False, index
=True,
801 info
=dict(description
="Critical hit rate bonus"))
802 ailment_chance
= Column(Integer
, nullable
=False, index
=True,
803 info
=dict(description
="Chance to cause an ailment, in percent"))
804 flinch_chance
= Column(Integer
, nullable
=False, index
=True,
805 info
=dict(description
="Chance to cause flinching, in percent"))
806 stat_chance
= Column(Integer
, nullable
=False, index
=True,
807 info
=dict(description
="Chance to cause a stat change, in percent"))
809 class MoveMetaAilment(TableBase
):
810 u
"""Common status ailments moves can inflict on a single Pokémon, including
811 major ailments like paralysis and minor ailments like trapping.
813 __tablename__
= 'move_meta_ailments'
814 __singlename__
= 'move_meta_ailment'
815 id = Column(Integer
, primary_key
=True, nullable
=False,
816 info
=dict(description
="A numeric ID"))
817 identifier
= Column(Unicode(24), nullable
=False,
818 info
=dict(description
="An identifier", format
='identifier'))
819 name
= TextColumn(Unicode(24), nullable
=False, index
=True, plural
='names',
820 info
=dict(description
="The name", format
='plaintext', official
=True))
822 class MoveMetaCategory(TableBase
):
823 u
"""Very general categories that loosely group move effects."""
824 __tablename__
= 'move_meta_categories'
825 __singlename__
= 'move_meta_category'
826 id = Column(Integer
, primary_key
=True, nullable
=False,
827 info
=dict(description
="A numeric ID"))
828 description
= ProseColumn(Unicode(64), plural
='descriptions', nullable
=False,
829 info
=dict(description
="A description of the category"))
831 class MoveMetaStatChange(TableBase
):
832 u
"""Stat changes moves (may) make."""
833 __tablename__
= 'move_meta_stat_changes'
834 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
835 info
=dict(description
="ID of the move"))
836 stat_id
= Column(Integer
, ForeignKey('stats.id'), primary_key
=True, nullable
=False, autoincrement
=False,
837 info
=dict(description
="ID of the stat"))
838 change
= Column(Integer
, nullable
=False, index
=True,
839 info
=dict(description
="Amount of increase/decrease, in stages"))
841 class MoveTarget(TableBase
):
842 u
"""Targetting or "range" of a move, e.g. "Affects all opponents" or "Affects user".
844 __tablename__
= 'move_targets'
845 __singlename__
= 'move_target'
846 id = Column(Integer
, primary_key
=True, nullable
=False,
847 info
=dict(description
="A numeric ID"))
848 identifier
= Column(Unicode(32), nullable
=False,
849 info
=dict(description
="An identifier", format
='identifier'))
850 description
= ProseColumn(Unicode(128), plural
='descriptions', nullable
=False,
851 info
=dict(description
="A description", format
='plaintext'))
852 name
= ProseColumn(Unicode(32), nullable
=False, index
=True, plural
='names',
853 info
=dict(description
="The name", format
='plaintext', official
=False))
855 class Move(TableBase
):
856 u
"""A Move: technique or attack a Pokémon can learn to use
858 __tablename__
= 'moves'
859 __singlename__
= 'move'
860 id = Column(Integer
, primary_key
=True, nullable
=False,
861 info
=dict(description
="A numeric ID"))
862 identifier
= Column(Unicode(24), nullable
=False,
863 info
=dict(description
="An identifier", format
='identifier'))
864 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False,
865 info
=dict(description
="ID of the generation this move first appeared in"))
866 type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=False,
867 info
=dict(description
="ID of the move's elemental type"))
868 power
= Column(SmallInteger
, nullable
=False,
869 info
=dict(description
="Base power of the move"))
870 pp
= Column(SmallInteger
, nullable
=True,
871 info
=dict(description
="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
872 accuracy
= Column(SmallInteger
, nullable
=True,
873 info
=dict(description
="Accuracy of the move; NULL means it never misses"))
874 priority
= Column(SmallInteger
, nullable
=False,
875 info
=dict(description
="The move's priority bracket"))
876 target_id
= Column(Integer
, ForeignKey('move_targets.id'), nullable
=False,
877 info
=dict(description
="ID of the target (range) of the move"))
878 damage_class_id
= Column(Integer
, ForeignKey('move_damage_classes.id'), nullable
=False,
879 info
=dict(description
="ID of the damage class (physical/special) of the move"))
880 effect_id
= Column(Integer
, ForeignKey('move_effects.id'), nullable
=False,
881 info
=dict(description
="ID of the move's effect"))
882 effect_chance
= Column(Integer
, nullable
=True,
883 info
=dict(description
="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
884 contest_type_id
= Column(Integer
, ForeignKey('contest_types.id'), nullable
=True,
885 info
=dict(description
="ID of the move's Contest type (e.g. cool or smart)"))
886 contest_effect_id
= Column(Integer
, ForeignKey('contest_effects.id'), nullable
=True,
887 info
=dict(description
="ID of the move's Contest effect"))
888 super_contest_effect_id
= Column(Integer
, ForeignKey('super_contest_effects.id'), nullable
=True,
889 info
=dict(description
="ID of the move's Super Contest effect"))
890 name
= TextColumn(Unicode(24), nullable
=False, index
=True, plural
='names',
891 info
=dict(description
="The name", format
='plaintext', official
=True))
893 class MoveChangelog(TableBase
):
894 """History of changes to moves across main game versions."""
895 __tablename__
= 'move_changelog'
896 __singlename__
= 'move_changelog'
897 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False,
898 info
=dict(description
="ID of the move that changed"))
899 changed_in_version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False,
900 info
=dict(description
="ID of the version group in which the move changed"))
901 type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=True,
902 info
=dict(description
="Prior type of the move, or NULL if unchanged"))
903 power
= Column(SmallInteger
, nullable
=True,
904 info
=dict(description
="Prior base power of the move, or NULL if unchanged"))
905 pp
= Column(SmallInteger
, nullable
=True,
906 info
=dict(description
="Prior base PP of the move, or NULL if unchanged"))
907 accuracy
= Column(SmallInteger
, nullable
=True,
908 info
=dict(description
="Prior accuracy of the move, or NULL if unchanged"))
909 effect_id
= Column(Integer
, ForeignKey('move_effects.id'), nullable
=True,
910 info
=dict(description
="Prior ID of the effect, or NULL if unchanged"))
911 effect_chance
= Column(Integer
, nullable
=True,
912 info
=dict(description
="Prior effect chance, or NULL if unchanged"))
914 class Nature(TableBase
):
915 u
"""A nature a Pokémon can have, such as Calm or Brave
917 __tablename__
= 'natures'
918 __singlename__
= 'nature'
919 id = Column(Integer
, primary_key
=True, nullable
=False,
920 info
=dict(description
="A numeric ID"))
921 identifier
= Column(Unicode(8), nullable
=False,
922 info
=dict(description
="An identifier", format
='identifier'))
923 decreased_stat_id
= Column(Integer
, ForeignKey('stats.id'), nullable
=False,
924 info
=dict(description
="ID of the stat that this nature decreases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
925 increased_stat_id
= Column(Integer
, ForeignKey('stats.id'), nullable
=False,
926 info
=dict(description
="ID of the stat that this nature increases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
927 hates_flavor_id
= Column(Integer
, ForeignKey('contest_types.id'), nullable
=False,
928 info
=dict(description
=u
"ID of the Berry flavor the Pokémon hates (if likes_flavor_id is the same, the effects cancel out)"))
929 likes_flavor_id
= Column(Integer
, ForeignKey('contest_types.id'), nullable
=False,
930 info
=dict(description
=u
"ID of the Berry flavor the Pokémon likes (if hates_flavor_id is the same, the effects cancel out)"))
931 name
= TextColumn(Unicode(8), nullable
=False, index
=True, plural
='names',
932 info
=dict(description
="The name", format
='plaintext', official
=True))
935 def is_neutral(self
):
936 u
"""Returns True iff this nature doesn't alter a Pokémon's stats,
937 bestow taste preferences, etc.
939 return self
.increased_stat_id
== self
.decreased_stat_id
941 class NatureBattleStylePreference(TableBase
):
942 u
"""Battle Palace move preference
944 Specifies how likely a Pokémon with a specific Nature is to use a move of
945 a particular battl style in Battle Palace or Battle Tent
947 __tablename__
= 'nature_battle_style_preferences'
948 nature_id
= Column(Integer
, ForeignKey('natures.id'), primary_key
=True, nullable
=False,
949 info
=dict(description
=u
"ID of the Pokémon's nature"))
950 move_battle_style_id
= Column(Integer
, ForeignKey('move_battle_styles.id'), primary_key
=True, nullable
=False,
951 info
=dict(description
="ID of the battle style"))
952 low_hp_preference
= Column(Integer
, nullable
=False,
953 info
=dict(description
=u
"Chance of using the move, in percent, if HP is under ½"))
954 high_hp_preference
= Column(Integer
, nullable
=False,
955 info
=dict(description
=u
"Chance of using the move, in percent, if HP is over ½"))
957 class NaturePokeathlonStat(TableBase
):
958 u
"""Specifies how a Nature affects a Pokéathlon stat
960 __tablename__
= 'nature_pokeathlon_stats'
961 nature_id
= Column(Integer
, ForeignKey('natures.id'), primary_key
=True, nullable
=False,
962 info
=dict(description
="ID of the nature"))
963 pokeathlon_stat_id
= Column(Integer
, ForeignKey('pokeathlon_stats.id'), primary_key
=True, nullable
=False,
964 info
=dict(description
="ID of the stat"))
965 max_change
= Column(Integer
, nullable
=False,
966 info
=dict(description
="Maximum change"))
968 class PokeathlonStat(TableBase
):
969 u
"""A Pokéathlon stat, such as "Stamina" or "Jump".
971 __tablename__
= 'pokeathlon_stats'
972 __singlename__
= 'pokeathlon_stat'
973 id = Column(Integer
, primary_key
=True, nullable
=False,
974 info
=dict(description
="A numeric ID"))
975 identifier
= Column(Unicode(8), nullable
=False,
976 info
=dict(description
="An identifier", format
='identifier'))
977 name
= TextColumn(Unicode(8), nullable
=False, index
=True, plural
='names',
978 info
=dict(description
="The name", format
='plaintext', official
=True))
980 class Pokedex(TableBase
):
981 u
"""A collection of Pokémon species ordered in a particular way
983 __tablename__
= 'pokedexes'
984 __singlename__
= 'pokedex'
985 id = Column(Integer
, primary_key
=True, nullable
=False,
986 info
=dict(description
="A numeric ID"))
987 region_id
= Column(Integer
, ForeignKey('regions.id'), nullable
=True,
988 info
=dict(description
=u
"ID of the region this Pokédex is used in, or None if it's global"))
989 identifier
= Column(Unicode(16), nullable
=False,
990 info
=dict(description
=u
"An identifier", format
='identifier'))
991 description
= ProseColumn(Unicode(512), plural
='descriptions', nullable
=False,
992 info
=dict(description
=u
"A longer description of the Pokédex", format
='plaintext'))
993 name
= ProseColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
994 info
=dict(description
="The name", format
='plaintext', official
=False))
996 class Pokemon(TableBase
):
997 u
"""A species of Pokémon. The core to this whole mess.
999 __tablename__
= 'pokemon'
1000 __singlename__
= 'pokemon'
1001 id = Column(Integer
, primary_key
=True, nullable
=False,
1002 info
=dict(description
=u
"A numeric ID"))
1003 identifier
= Column(Unicode(20), nullable
=False,
1004 info
=dict(description
=u
"An identifier", format
='identifier'))
1005 generation_id
= Column(Integer
, ForeignKey('generations.id'),
1006 info
=dict(description
=u
"ID of the generation this species first appeared in"))
1007 evolution_chain_id
= Column(Integer
, ForeignKey('evolution_chains.id'),
1008 info
=dict(description
=u
"ID of the species' evolution chain (a.k.a. family)"))
1009 height
= Column(Integer
, nullable
=False,
1010 info
=dict(description
=u
"The height of the Pokémon, in decimeters (tenths of a meter)"))
1011 weight
= Column(Integer
, nullable
=False,
1012 info
=dict(description
=u
"The weight of the Pokémon, in tenths of a kilogram (decigrams)"))
1013 species
= TextColumn(Unicode(16), nullable
=False, plural
='species_names',
1014 info
=dict(description
=u
'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
1015 official
=True, format
='plaintext'))
1016 color_id
= Column(Integer
, ForeignKey('pokemon_colors.id'), nullable
=False,
1017 info
=dict(description
=u
"ID of this Pokémon's Pokédex color, as used for a gimmick search function in the games."))
1018 pokemon_shape_id
= Column(Integer
, ForeignKey('pokemon_shapes.id'), nullable
=True,
1019 info
=dict(description
=u
"ID of this Pokémon's body shape, as used for a gimmick search function in the games."))
1020 habitat_id
= Column(Integer
, ForeignKey('pokemon_habitats.id'), nullable
=True,
1021 info
=dict(description
=u
"ID of this Pokémon's habitat, as used for a gimmick search function in the games."))
1022 gender_rate
= Column(Integer
, nullable
=False,
1023 info
=dict(description
=u
"The chance of this Pokémon being female, in eighths; or -1 for genderless"))
1024 capture_rate
= Column(Integer
, nullable
=False,
1025 info
=dict(description
=u
"The base capture rate; up to 255"))
1026 base_experience
= Column(Integer
, nullable
=False,
1027 info
=dict(description
=u
"The base EXP gained when defeating this Pokémon")) # XXX: Is this correct?
1028 base_happiness
= Column(Integer
, nullable
=False,
1029 info
=dict(description
=u
"The tameness when caught by a normal ball"))
1030 is_baby
= Column(Boolean
, nullable
=False,
1031 info
=dict(description
=u
"True iff the Pokémon is a baby, i.e. a lowest-stage Pokémon that cannot breed but whose evolved form can."))
1032 hatch_counter
= Column(Integer
, nullable
=False,
1033 info
=dict(description
=u
"Initial hatch counter: one must walk 255 × (hatch_counter + 1) steps before this Pokémon's egg hatches, unless utilizing bonuses like Flame Body's"))
1034 has_gender_differences
= Column(Boolean
, nullable
=False,
1035 info
=dict(description
=u
"Set iff the species exhibits enough sexual dimorphism to have separate sets of sprites in Gen IV and beyond."))
1036 order
= Column(Integer
, nullable
=False, index
=True,
1037 info
=dict(description
=u
"Order for sorting. Almost national order, except families and forms are grouped together."))
1038 name
= TextColumn(Unicode(20), nullable
=False, index
=True, plural
='names',
1039 info
=dict(description
="The name", format
='plaintext', official
=True))
1041 ### Stuff to handle alternate Pokémon forms
1045 u
"""Returns the Pokémon's form, using its default form as fallback."""
1047 return self
.unique_form
or self
.default_form
1050 def is_base_form(self
):
1051 u
"""Returns True iff the Pokémon is the base form for its species,
1055 return self
.unique_form
is None or self
.unique_form
.is_default
1058 def form_name(self
):
1059 u
"""Returns the Pokémon's form name if it represents a particular form
1060 and that form has a name, or None otherwise.
1063 # If self.unique_form is None, the short-circuit "and" will go ahead
1064 # and return that. Otherwise, it'll return the form's name, which may
1066 return self
.unique_form
and self
.unique_form
.name
1069 def full_name(self
):
1070 u
"""Returns the Pokémon's name, including its form if applicable."""
1073 return u
'{0} {1}'.format(self
.form_name
, self
.name
)
1078 def normal_form(self
):
1079 u
"""Returns the normal form for this Pokémon; i.e., this will return
1080 regular Deoxys when called on any Deoxys form.
1083 if self
.unique_form
:
1084 return self
.unique_form
.form_base_pokemon
1089 def stat(self
, stat_name
):
1090 u
"""Returns a PokemonStat record for the given stat name (or Stat row
1091 object). Uses the normal has-many machinery, so all the stats are
1094 if isinstance(stat_name
, Stat
):
1095 stat_name
= stat_name
.name
1097 for pokemon_stat
in self
.stats
:
1098 if pokemon_stat
.stat
.name
== stat_name
:
1101 raise KeyError(u
'No stat named %s' % stat_name
)
1104 def better_damage_class(self
):
1105 u
"""Returns the MoveDamageClass that this Pokémon is best suited for,
1106 based on its attack stats.
1108 If the attack stats are about equal (within 5), returns None. The
1109 value None, not the damage class called 'None'.
1111 phys
= self
.stat(u
'Attack')
1112 spec
= self
.stat(u
'Special Attack')
1114 diff
= phys
.base_stat
- spec
.base_stat
1117 return phys
.stat
.damage_class
1119 return spec
.stat
.damage_class
1123 class PokemonAbility(TableBase
):
1124 u
"""Maps an ability to a Pokémon that can have it
1126 __tablename__
= 'pokemon_abilities'
1127 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1128 info
=dict(description
=u
"ID of the Pokémon"))
1129 ability_id
= Column(Integer
, ForeignKey('abilities.id'), nullable
=False,
1130 info
=dict(description
=u
"ID of the ability"))
1131 # XXX having both a method and a slot is kind of gross. "slot" is a
1132 # misnomer, anyway: duplicate abilities don't appear in slot 2.
1133 # Probably should replace that with "order".
1134 is_dream
= Column(Boolean
, nullable
=False, index
=True,
1135 info
=dict(description
=u
"Whether this is a Dream World ability"))
1136 slot
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
1137 info
=dict(description
=u
"The ability slot, i.e. 1 or 2 for gen. IV"))
1139 class PokemonColor(TableBase
):
1140 u
"""The "Pokédex color" of a Pokémon species. Usually based on the Pokémon's color.
1142 __tablename__
= 'pokemon_colors'
1143 __singlename__
= 'pokemon_color'
1144 id = Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
1145 info
=dict(description
=u
"ID of the Pokémon"))
1146 identifier
= Column(Unicode(6), nullable
=False,
1147 info
=dict(description
=u
"An identifier", format
='identifier'))
1148 name
= TextColumn(Unicode(6), nullable
=False, index
=True, plural
='names',
1149 info
=dict(description
="The name", format
='plaintext', official
=True))
1151 class PokemonDexNumber(TableBase
):
1152 u
"""The number of a Pokémon in a particular Pokédex (e.g. Jigglypuff is #138 in Hoenn's 'dex)
1154 __tablename__
= 'pokemon_dex_numbers'
1155 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1156 info
=dict(description
=u
"ID of the Pokémon"))
1157 pokedex_id
= Column(Integer
, ForeignKey('pokedexes.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1158 info
=dict(description
=u
"ID of the Pokédex"))
1159 pokedex_number
= Column(Integer
, nullable
=False,
1160 info
=dict(description
=u
"Number of the Pokémon in that the Pokédex"))
1162 class PokemonEggGroup(TableBase
):
1163 u
"""Maps an Egg group to a Pokémon; each Pokémon belongs to one or two egg groups
1165 __tablename__
= 'pokemon_egg_groups'
1166 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1167 info
=dict(description
=u
"ID of the Pokémon"))
1168 egg_group_id
= Column(Integer
, ForeignKey('egg_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1169 info
=dict(description
=u
"ID of the egg group"))
1171 class PokemonEvolution(TableBase
):
1172 u
"""A required action ("trigger") and the conditions under which the trigger
1173 must occur to cause a Pokémon to evolve.
1175 Any condition may be null if it does not apply for a particular Pokémon.
1177 __tablename__
= 'pokemon_evolution'
1178 from_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=False,
1179 info
=dict(description
=u
"The ID of the pre-evolution Pokémon."))
1180 to_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1181 info
=dict(description
=u
"The ID of the post-evolution Pokémon."))
1182 evolution_trigger_id
= Column(Integer
, ForeignKey('evolution_triggers.id'), nullable
=False,
1183 info
=dict(description
=u
"The ID of the evolution trigger."))
1184 trigger_item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=True,
1185 info
=dict(description
=u
"The ID of the item that must be used on the Pokémon."))
1186 minimum_level
= Column(Integer
, nullable
=True,
1187 info
=dict(description
=u
"The minimum level for the Pokémon."))
1188 gender
= Column(Enum('male', 'female', name
='pokemon_evolution_gender'), nullable
=True,
1189 info
=dict(description
=u
"The Pokémon's required gender, or None if gender doesn't matter"))
1190 location_id
= Column(Integer
, ForeignKey('locations.id'), nullable
=True,
1191 info
=dict(description
=u
"The ID of the location the evolution must be triggered at."))
1192 held_item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=True,
1193 info
=dict(description
=u
"The ID of the item the Pokémon must hold."))
1194 time_of_day
= Column(Enum('day', 'night', name
='pokemon_evolution_time_of_day'), nullable
=True,
1195 info
=dict(description
=u
"The required time of day."))
1196 known_move_id
= Column(Integer
, ForeignKey('moves.id'), nullable
=True,
1197 info
=dict(description
=u
"The ID of the move the Pokémon must know."))
1198 minimum_happiness
= Column(Integer
, nullable
=True,
1199 info
=dict(description
=u
"The minimum happiness value the Pokémon must have."))
1200 minimum_beauty
= Column(Integer
, nullable
=True,
1201 info
=dict(description
=u
"The minimum Beauty value the Pokémon must have."))
1202 relative_physical_stats
= Column(Integer
, nullable
=True,
1203 info
=dict(description
=u
"The required relation between the Pokémon's Attack and Defense stats, as sgn(atk-def)."))
1204 party_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=True,
1205 info
=dict(description
=u
"The ID of the Pokémon that must be present in the party."))
1206 trade_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=True,
1207 info
=dict(description
=u
"The ID of the Pokémon for which this Pokémon must be traded."))
1209 class PokemonFlavorText(TableBase
, LanguageSpecific
):
1210 u
"""In-game Pokédex descrption of a Pokémon.
1212 __tablename__
= 'pokemon_flavor_text'
1213 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1214 info
=dict(description
=u
"ID of the Pokémon"))
1215 version_id
= Column(Integer
, ForeignKey('versions.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1216 info
=dict(description
=u
"ID of the version that has this flavor text"))
1217 flavor_text
= Column(Unicode(255), nullable
=False,
1218 info
=dict(description
=u
"ID of the version that has this flavor text", official
=True, format
='gametext'))
1220 class PokemonForm(TableBase
):
1221 u
"""An individual form of a Pokémon.
1223 Pokémon that do not have separate forms are still given a single row to
1224 represent their single form.
1226 __tablename__
= 'pokemon_forms'
1227 __singlename__
= 'pokemon_form'
1228 id = Column(Integer
, primary_key
=True, nullable
=False,
1229 info
=dict(description
=u
'A unique ID for this form.'))
1230 identifier
= Column(Unicode(16), nullable
=True,
1231 info
=dict(description
=u
"An identifier", format
='identifier'))
1232 form_base_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=False, autoincrement
=False,
1233 info
=dict(description
=u
'The ID of the base Pokémon for this form.'))
1234 unique_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), autoincrement
=False,
1235 info
=dict(description
=u
'The ID of a Pokémon that represents specifically this form, for Pokémon with functionally-different forms like Wormadam.'))
1236 introduced_in_version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), autoincrement
=False,
1237 info
=dict(description
=u
'The ID of the version group in which this form first appeared.'))
1238 is_default
= Column(Boolean
, nullable
=False,
1239 info
=dict(description
=u
'Set for exactly one form used as the default for each species.'))
1240 order
= Column(Integer
, nullable
=False, autoincrement
=False,
1241 info
=dict(description
=u
'The order in which forms should be sorted. Multiple forms may have equal order, in which case they should fall back on sorting by name.'))
1242 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
1243 info
=dict(description
="The name", format
='plaintext', official
=True))
1247 u
"""Returns the Pokémon for this form, using the form base as fallback.
1250 return self
.unique_pokemon
or self
.form_base_pokemon
1253 def full_name(self
):
1254 u
"""Returns the full name of this form, e.g. "Plant Cloak"."""
1258 elif self
.form_group
and self
.form_group
.term
:
1259 return u
'{0} {1}'.format(self
.name
, self
.form_group
.term
)
1264 def pokemon_name(self
):
1265 u
"""Returns the name of this Pokémon with this form, e.g. "Plant
1270 return u
'{0} {1}'.format(self
.name
, self
.form_base_pokemon
.name
)
1272 return self
.form_base_pokemon
.name
1274 class PokemonFormGroup(TableBase
):
1275 u
"""Information about a Pokémon's forms as a group."""
1276 __tablename__
= 'pokemon_form_groups'
1277 __singlename__
= 'pokemon_form_group'
1278 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1279 info
=dict(description
=u
"ID of the base form Pokémon"))
1280 term
= ProseColumn(Unicode(16), plural
='terms', nullable
=True,
1281 info
=dict(description
=u
"The term for this Pokémon's forms, e.g. \"Cloak\" for Burmy or \"Forme\" for Deoxys.", official
=True, format
='plaintext'))
1282 is_battle_only
= Column(Boolean
, nullable
=False,
1283 info
=dict(description
=u
"Set iff the forms only change in battle"))
1284 description
= ProseColumn(markdown
.MarkdownColumn(1024), plural
='descriptions', nullable
=False,
1285 info
=dict(description
=u
"Description of how the forms work", format
='markdown'))
1286 PokemonFormGroup
.id = PokemonFormGroup
.pokemon_id
1288 class PokemonFormPokeathlonStat(TableBase
):
1289 u
"""A Pokémon form's performance in one Pokéathlon stat."""
1290 __tablename__
= 'pokemon_form_pokeathlon_stats'
1291 pokemon_form_id
= Column(Integer
, ForeignKey('pokemon_forms.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1292 info
=dict(description
=u
'The ID of the Pokémon form.'))
1293 pokeathlon_stat_id
= Column(Integer
, ForeignKey('pokeathlon_stats.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1294 info
=dict(description
=u
'The ID of the Pokéathlon stat.'))
1295 minimum_stat
= Column(Integer
, nullable
=False, autoincrement
=False,
1296 info
=dict(description
=u
'The minimum value for this stat for this Pokémon form.'))
1297 base_stat
= Column(Integer
, nullable
=False, autoincrement
=False,
1298 info
=dict(description
=u
'The default value for this stat for this Pokémon form.'))
1299 maximum_stat
= Column(Integer
, nullable
=False, autoincrement
=False,
1300 info
=dict(description
=u
'The maximum value for this stat for this Pokémon form.'))
1302 class PokemonHabitat(TableBase
):
1303 u
"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex
1305 __tablename__
= 'pokemon_habitats'
1306 __singlename__
= 'pokemon_habitat'
1307 id = Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
1308 info
=dict(description
=u
"A numeric ID"))
1309 identifier
= Column(Unicode(16), nullable
=False,
1310 info
=dict(description
=u
"An identifier", format
='identifier'))
1311 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
1312 info
=dict(description
="The name", format
='plaintext', official
=True))
1314 class PokemonInternalID(TableBase
):
1315 u
"""The number of a Pokémon a game uses internally
1317 __tablename__
= 'pokemon_internal_ids'
1318 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, autoincrement
=False, nullable
=False,
1319 info
=dict(description
=u
"Database ID of the Pokémon"))
1320 generation_id
= Column(Integer
, ForeignKey('generations.id'), primary_key
=True, autoincrement
=False, nullable
=False,
1321 info
=dict(description
=u
"Database ID of the generation"))
1322 internal_id
= Column(Integer
, nullable
=False,
1323 info
=dict(description
=u
"Internal ID the generation's games use for the Pokémon"))
1325 class PokemonItem(TableBase
):
1326 u
"""Record of an item a Pokémon can hold in the wild
1328 __tablename__
= 'pokemon_items'
1329 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1330 info
=dict(description
=u
"ID of the Pokémon"))
1331 version_id
= Column(Integer
, ForeignKey('versions.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1332 info
=dict(description
=u
"ID of the version this applies to"))
1333 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1334 info
=dict(description
=u
"ID of the item"))
1335 rarity
= Column(Integer
, nullable
=False,
1336 info
=dict(description
=u
"Chance of the Pokémon holding the item, in percent"))
1338 class PokemonMove(TableBase
):
1339 u
"""Record of a move a Pokémon can learn
1341 __tablename__
= 'pokemon_moves'
1342 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=False, index
=True,
1343 info
=dict(description
=u
"ID of the Pokémon"))
1344 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False, index
=True,
1345 info
=dict(description
=u
"ID of the version group this applies to"))
1346 move_id
= Column(Integer
, ForeignKey('moves.id'), nullable
=False, index
=True,
1347 info
=dict(description
=u
"ID of the move"))
1348 pokemon_move_method_id
= Column(Integer
, ForeignKey('pokemon_move_methods.id'), nullable
=False, index
=True,
1349 info
=dict(description
=u
"ID of the method this move is learned by"))
1350 level
= Column(Integer
, nullable
=True, index
=True,
1351 info
=dict(description
=u
"Level the move is learned at, if applicable"))
1352 order
= Column(Integer
, nullable
=True,
1353 info
=dict(description
=u
"A sort key to produce the correct ordering when all else is equal")) # XXX: This needs a better description
1356 PrimaryKeyConstraint('pokemon_id', 'version_group_id', 'move_id', 'pokemon_move_method_id', 'level'),
1360 class PokemonMoveMethod(TableBase
):
1361 u
"""A method a move can be learned by, such as "Level up" or "Tutor".
1363 __tablename__
= 'pokemon_move_methods'
1364 __singlename__
= 'pokemon_move_method'
1365 id = Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
1366 info
=dict(description
=u
"A numeric ID"))
1367 identifier
= Column(Unicode(64), nullable
=False,
1368 info
=dict(description
=u
"An identifier", format
='identifier'))
1369 description
= ProseColumn(Unicode(255), plural
='descriptions', nullable
=False,
1370 info
=dict(description
=u
"A detailed description of how the method works", format
='plaintext'))
1371 name
= ProseColumn(Unicode(64), nullable
=False, index
=True, plural
='names',
1372 info
=dict(description
="The name", format
='plaintext', official
=False))
1374 class PokemonShape(TableBase
):
1375 u
"""The shape of a Pokémon's body, as used in generation IV Pokédexes.
1377 __tablename__
= 'pokemon_shapes'
1378 __singlename__
= 'pokemon_shape'
1379 id = Column(Integer
, primary_key
=True, nullable
=False,
1380 info
=dict(description
=u
"A numeric ID"))
1381 identifier
= Column(Unicode(24), nullable
=False,
1382 info
=dict(description
=u
"An identifier", format
='identifier'))
1383 awesome_name
= ProseColumn(Unicode(16), plural
='awesome_names', nullable
=False,
1384 info
=dict(description
=u
"A splendiferous name of the body shape", format
='plaintext'))
1385 name
= ProseColumn(Unicode(24), nullable
=False, index
=True, plural
='names',
1386 info
=dict(description
="The name", format
='plaintext', official
=False))
1388 class PokemonStat(TableBase
):
1389 u
"""A stat value of a Pokémon
1391 __tablename__
= 'pokemon_stats'
1392 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1393 info
=dict(description
=u
"ID of the Pokémon"))
1394 stat_id
= Column(Integer
, ForeignKey('stats.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1395 info
=dict(description
=u
"ID of the stat"))
1396 base_stat
= Column(Integer
, nullable
=False,
1397 info
=dict(description
=u
"The base stat"))
1398 effort
= Column(Integer
, nullable
=False,
1399 info
=dict(description
=u
"The effort increase in this stat gained when this Pokémon is defeated"))
1401 class PokemonType(TableBase
):
1402 u
"""Maps a type to a Pokémon. Each Pokémon has 1 or 2 types.
1404 __tablename__
= 'pokemon_types'
1405 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1406 info
=dict(description
=u
"ID of the Pokémon"))
1407 type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=False,
1408 info
=dict(description
=u
"ID of the type"))
1409 slot
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False,
1410 info
=dict(description
=u
"The type's slot, 1 or 2, used to sort types if there are two of them"))
1412 class Region(TableBase
):
1413 u
"""Major areas of the world: Kanto, Johto, etc.
1415 __tablename__
= 'regions'
1416 __singlename__
= 'region'
1417 id = Column(Integer
, primary_key
=True, nullable
=False,
1418 info
=dict(description
=u
"A numeric ID"))
1419 identifier
= Column(Unicode(16), nullable
=False,
1420 info
=dict(description
=u
"An identifier", format
='identifier'))
1421 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
1422 info
=dict(description
="The name", format
='plaintext', official
=True))
1424 class Stat(TableBase
):
1425 u
"""A Stat, such as Attack or Speed
1427 __tablename__
= 'stats'
1428 __singlename__
= 'stat'
1429 id = Column(Integer
, primary_key
=True, nullable
=False,
1430 info
=dict(description
=u
"A numeric ID"))
1431 damage_class_id
= Column(Integer
, ForeignKey('move_damage_classes.id'), nullable
=True,
1432 info
=dict(description
=u
"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
1433 identifier
= Column(Unicode(16), nullable
=False,
1434 info
=dict(description
=u
"An identifier", format
='identifier'))
1435 name
= TextColumn(Unicode(16), nullable
=False, index
=True, plural
='names',
1436 info
=dict(description
="The name", format
='plaintext', official
=True))
1438 class StatHint(TableBase
):
1439 u
"""Flavor text for genes that appears in a Pokémon's summary. Sometimes
1440 called "characteristics".
1442 __tablename__
= 'stat_hints'
1443 __singlename__
= 'stat_hint'
1444 id = Column(Integer
, primary_key
=True, nullable
=False,
1445 info
=dict(description
=u
"A numeric ID"))
1446 stat_id
= Column(Integer
, ForeignKey('stats.id'), nullable
=False,
1447 info
=dict(description
=u
"ID of the highest stat"))
1448 gene_mod_5
= Column(Integer
, nullable
=False, index
=True,
1449 info
=dict(description
=u
"Value of the highest stat modulo 5"))
1450 message
= TextColumn(Unicode(24), plural
='messages', nullable
=False, index
=True, unique
=True,
1451 info
=dict(description
=u
"The text displayed", official
=True, format
='plaintext'))
1453 class SuperContestCombo(TableBase
):
1454 u
"""Combo of two moves in a Super Contest.
1456 __tablename__
= 'super_contest_combos'
1457 first_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1458 info
=dict(description
=u
"The ID of the first move in the combo."))
1459 second_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1460 info
=dict(description
=u
"The ID of the second and last move."))
1462 class SuperContestEffect(TableBase
):
1463 u
"""An effect a move can have when used in the Super Contest
1465 __tablename__
= 'super_contest_effects'
1466 __singlename__
= 'super_contest_effect'
1467 id = Column(Integer
, primary_key
=True, nullable
=False,
1468 info
=dict(description
=u
"This effect's unique ID."))
1469 appeal
= Column(SmallInteger
, nullable
=False,
1470 info
=dict(description
=u
"The number of hearts the user gains."))
1471 flavor_text
= ProseColumn(Unicode(64), plural
='flavor_texts', nullable
=False,
1472 info
=dict(description
=u
"A description of the effect.", format
='plaintext'))
1474 class TypeEfficacy(TableBase
):
1475 u
"""The damage multiplier used when a move of a particular type damages a
1476 Pokémon of a particular other type.
1478 __tablename__
= 'type_efficacy'
1479 damage_type_id
= Column(Integer
, ForeignKey('types.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1480 info
=dict(description
=u
"The ID of the damaging type."))
1481 target_type_id
= Column(Integer
, ForeignKey('types.id'), primary_key
=True, nullable
=False, autoincrement
=False,
1482 info
=dict(description
=u
"The ID of the defending Pokémon's type."))
1483 damage_factor
= Column(Integer
, nullable
=False,
1484 info
=dict(description
=u
"The multiplier, as a percentage of damage inflicted."))
1486 class Type(TableBase
):
1487 u
"""Any of the elemental types Pokémon and moves can have."""
1488 __tablename__
= 'types'
1489 __singlename__
= 'type'
1490 id = Column(Integer
, primary_key
=True, nullable
=False,
1491 info
=dict(description
=u
"A unique ID for this type."))
1492 identifier
= Column(Unicode(12), nullable
=False,
1493 info
=dict(description
=u
"An identifier", format
='identifier'))
1494 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False,
1495 info
=dict(description
=u
"The ID of the generation this type first appeared in."))
1496 damage_class_id
= Column(Integer
, ForeignKey('move_damage_classes.id'), nullable
=True,
1497 info
=dict(description
=u
"The ID of the damage class this type's moves had before Generation IV, null if not applicable (e.g. ???)."))
1498 name
= TextColumn(Unicode(12), nullable
=False, index
=True, plural
='names',
1499 info
=dict(description
="The name", format
='plaintext', official
=True))
1501 class VersionGroup(TableBase
):
1502 u
"""A group of versions, containing either two paired versions (such as Red
1503 and Blue) or a single game (such as Yellow.)
1505 __tablename__
= 'version_groups'
1506 id = Column(Integer
, primary_key
=True, nullable
=False,
1507 info
=dict(description
=u
"This version group's unique ID."))
1508 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False,
1509 info
=dict(description
=u
"The ID of the generation the games in this group belong to."))
1510 pokedex_id
= Column(Integer
, ForeignKey('pokedexes.id'), nullable
=False,
1511 info
=dict(description
=u
"The ID of the regional Pokédex used in this version group."))
1513 class VersionGroupRegion(TableBase
):
1514 u
"""Maps a version group to a region that appears in it."""
1515 __tablename__
= 'version_group_regions'
1516 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False,
1517 info
=dict(description
=u
"The ID of the version group."))
1518 region_id
= Column(Integer
, ForeignKey('regions.id'), primary_key
=True, nullable
=False,
1519 info
=dict(description
=u
"The ID of the region."))
1521 class Version(TableBase
):
1522 u
"""An individual main-series Pokémon game."""
1523 __tablename__
= 'versions'
1524 __singlename__
= 'version'
1525 id = Column(Integer
, primary_key
=True, nullable
=False,
1526 info
=dict(description
=u
"A unique ID for this version."))
1527 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False,
1528 info
=dict(description
=u
"The ID of the version group this game belongs to."))
1529 identifier
= Column(Unicode(32), nullable
=False,
1530 info
=dict(description
=u
'And identifier', format
='identifier'))
1531 name
= TextColumn(Unicode(32), nullable
=False, index
=True, plural
='names',
1532 info
=dict(description
="The name", format
='plaintext', official
=True))
1535 ### Relations down here, to avoid ordering problems
1536 Ability
.changelog
= relation(AbilityChangelog
,
1537 order_by
=AbilityChangelog
.changed_in_version_group_id
.desc(),
1540 Ability
.flavor_text
= relation(AbilityFlavorText
, order_by
=AbilityFlavorText
.version_group_id
, backref
='ability')
1541 Ability
.generation
= relation(Generation
, backref
='abilities')
1542 Ability
.all_pokemon
= relation(Pokemon
,
1543 secondary
=PokemonAbility
.__table__
,
1544 order_by
=Pokemon
.order
,
1545 back_populates
='all_abilities',
1547 Ability
.pokemon
= relation(Pokemon
,
1548 secondary
=PokemonAbility
.__table__
,
1550 PokemonAbility
.ability_id
== Ability
.id,
1551 PokemonAbility
.is_dream
== False
1553 order_by
=Pokemon
.order
,
1554 back_populates
='abilities',
1556 Ability
.dream_pokemon
= relation(Pokemon
,
1557 secondary
=PokemonAbility
.__table__
,
1559 PokemonAbility
.ability_id
== Ability
.id,
1560 PokemonAbility
.is_dream
== True
1562 order_by
=Pokemon
.order
,
1563 back_populates
='dream_ability',
1566 AbilityChangelog
.changed_in
= relation(VersionGroup
, backref
='ability_changelog')
1568 AbilityFlavorText
.version_group
= relation(VersionGroup
)
1570 Berry
.berry_firmness
= relation(BerryFirmness
, backref
='berries')
1571 Berry
.firmness
= association_proxy('berry_firmness', 'name')
1572 Berry
.flavors
= relation(BerryFlavor
, order_by
=BerryFlavor
.contest_type_id
, backref
='berry')
1573 Berry
.natural_gift_type
= relation(Type
)
1575 BerryFlavor
.contest_type
= relation(ContestType
)
1577 ContestCombo
.first
= relation(Move
, primaryjoin
=ContestCombo
.first_move_id
==Move
.id,
1578 backref
='contest_combo_first')
1579 ContestCombo
.second
= relation(Move
, primaryjoin
=ContestCombo
.second_move_id
==Move
.id,
1580 backref
='contest_combo_second')
1582 Encounter
.location_area
= relation(LocationArea
, backref
='encounters')
1583 Encounter
.pokemon
= relation(Pokemon
, backref
='encounters')
1584 Encounter
.version
= relation(Version
, backref
='encounters')
1585 Encounter
.slot
= relation(EncounterSlot
, backref
='encounters')
1587 EncounterConditionValue
.condition
= relation(EncounterCondition
, backref
='values')
1589 Encounter
.condition_value_map
= relation(EncounterConditionValueMap
, backref
='encounter')
1590 Encounter
.condition_values
= association_proxy('condition_value_map', 'condition_value')
1591 EncounterConditionValueMap
.condition_value
= relation(EncounterConditionValue
,
1592 backref
='encounter_map')
1594 EncounterSlot
.terrain
= relation(EncounterTerrain
, backref
='slots')
1595 EncounterSlot
.version_group
= relation(VersionGroup
)
1597 EvolutionChain
.growth_rate
= relation(GrowthRate
, backref
='evolution_chains')
1598 EvolutionChain
.baby_trigger_item
= relation(Item
, backref
='evolution_chains')
1599 EvolutionChain
.pokemon
= relation(Pokemon
, order_by
=Pokemon
.order
, back_populates
='evolution_chain')
1601 Experience
.growth_rate
= relation(GrowthRate
, backref
='experience_table')
1603 Generation
.canonical_pokedex
= relation(Pokedex
, backref
='canonical_for_generation')
1604 Generation
.versions
= relation(Version
, secondary
=VersionGroup
.__table__
)
1605 Generation
.main_region
= relation(Region
)
1607 GrowthRate
.max_experience_obj
= relation(Experience
, primaryjoin
=and_(Experience
.growth_rate_id
== GrowthRate
.id, Experience
.level
== 100), uselist
=False)
1608 GrowthRate
.max_experience
= association_proxy('max_experience_obj', 'experience')
1610 Item
.berry
= relation(Berry
, uselist
=False, backref
='item')
1611 Item
.flags
= relation(ItemFlag
, secondary
=ItemFlagMap
.__table__
)
1612 Item
.flavor_text
= relation(ItemFlavorText
, order_by
=ItemFlavorText
.version_group_id
.asc(), backref
='item')
1613 Item
.fling_effect
= relation(ItemFlingEffect
, backref
='items')
1614 Item
.machines
= relation(Machine
, order_by
=Machine
.version_group_id
.asc())
1615 Item
.category
= relation(ItemCategory
)
1616 Item
.pocket
= association_proxy('category', 'pocket')
1618 ItemCategory
.items
= relation(Item
, order_by
=Item
.identifier
)
1619 ItemCategory
.pocket
= relation(ItemPocket
)
1621 ItemFlavorText
.version_group
= relation(VersionGroup
)
1623 ItemInternalID
.item
= relation(Item
, backref
='internal_ids')
1624 ItemInternalID
.generation
= relation(Generation
)
1626 ItemPocket
.categories
= relation(ItemCategory
, order_by
=ItemCategory
.identifier
)
1628 Location
.region
= relation(Region
, backref
='locations')
1630 LocationArea
.location
= relation(Location
, backref
='areas')
1632 LocationInternalID
.location
= relation(Location
, backref
='internal_ids')
1633 LocationInternalID
.generation
= relation(Generation
)
1635 Machine
.item
= relation(Item
)
1636 Machine
.version_group
= relation(VersionGroup
)
1638 Move
.changelog
= relation(MoveChangelog
,
1639 order_by
=MoveChangelog
.changed_in_version_group_id
.desc(),
1642 Move
.contest_effect
= relation(ContestEffect
, backref
='moves')
1643 Move
.contest_combo_next
= association_proxy('contest_combo_first', 'second')
1644 Move
.contest_combo_prev
= association_proxy('contest_combo_second', 'first')
1645 Move
.contest_type
= relation(ContestType
, backref
='moves')
1646 Move
.damage_class
= relation(MoveDamageClass
, backref
='moves')
1647 Move
.flags
= association_proxy('move_flags', 'flag')
1648 Move
.flavor_text
= relation(MoveFlavorText
, order_by
=MoveFlavorText
.version_group_id
, backref
='move')
1649 Move
.generation
= relation(Generation
, backref
='moves')
1650 Move
.machines
= relation(Machine
, backref
='move')
1651 Move
.meta
= relation(MoveMeta
, uselist
=False, backref
='move')
1652 Move
.meta_stat_changes
= relation(MoveMetaStatChange
)
1653 Move
.move_effect
= relation(MoveEffect
, backref
='moves')
1654 Move
.move_flags
= relation(MoveFlag
, backref
='move')
1655 Move
.super_contest_effect
= relation(SuperContestEffect
, backref
='moves')
1656 Move
.super_contest_combo_next
= association_proxy('super_contest_combo_first', 'second')
1657 Move
.super_contest_combo_prev
= association_proxy('super_contest_combo_second', 'first')
1658 Move
.target
= relation(MoveTarget
, backref
='moves')
1659 Move
.type = relation(Type
, back_populates
='moves')
1661 MoveChangelog
.changed_in
= relation(VersionGroup
, backref
='move_changelog')
1662 MoveChangelog
.move_effect
= relation(MoveEffect
, backref
='move_changelog')
1663 MoveChangelog
.type = relation(Type
, backref
='move_changelog')
1665 MoveEffect
.category_map
= relation(MoveEffectCategoryMap
)
1666 MoveEffect
.categories
= association_proxy('category_map', 'category')
1667 MoveEffect
.changelog
= relation(MoveEffectChangelog
,
1668 order_by
=MoveEffectChangelog
.changed_in_version_group_id
.desc(),
1669 backref
='move_effect',
1671 MoveEffectCategoryMap
.category
= relation(MoveEffectCategory
)
1673 MoveEffectChangelog
.changed_in
= relation(VersionGroup
, backref
='move_effect_changelog')
1675 MoveFlag
.flag
= relation(MoveFlagType
)
1677 MoveFlavorText
.version_group
= relation(VersionGroup
)
1679 MoveMeta
.category
= relation(MoveMetaCategory
, backref
='move_meta')
1680 MoveMeta
.ailment
= relation(MoveMetaAilment
, backref
='move_meta')
1682 MoveMetaStatChange
.stat
= relation(Stat
, backref
='move_meta_stat_changes')
1684 Nature
.decreased_stat
= relation(Stat
, primaryjoin
=Nature
.decreased_stat_id
==Stat
.id,
1685 backref
='decreasing_natures')
1686 Nature
.increased_stat
= relation(Stat
, primaryjoin
=Nature
.increased_stat_id
==Stat
.id,
1687 backref
='increasing_natures')
1688 Nature
.hates_flavor
= relation(ContestType
, primaryjoin
=Nature
.hates_flavor_id
==ContestType
.id,
1689 backref
='hating_natures')
1690 Nature
.likes_flavor
= relation(ContestType
, primaryjoin
=Nature
.likes_flavor_id
==ContestType
.id,
1691 backref
='liking_natures')
1692 Nature
.battle_style_preferences
= relation(NatureBattleStylePreference
,
1693 order_by
=NatureBattleStylePreference
.move_battle_style_id
,
1695 Nature
.pokeathlon_effects
= relation(NaturePokeathlonStat
, order_by
=NaturePokeathlonStat
.pokeathlon_stat_id
)
1697 NatureBattleStylePreference
.battle_style
= relation(MoveBattleStyle
, backref
='nature_preferences')
1699 NaturePokeathlonStat
.pokeathlon_stat
= relation(PokeathlonStat
, backref
='nature_effects')
1701 Pokedex
.region
= relation(Region
, backref
='pokedexes')
1702 Pokedex
.version_groups
= relation(VersionGroup
, order_by
=VersionGroup
.id, back_populates
='pokedex')
1704 Pokemon
.all_abilities
= relation(Ability
,
1705 secondary
=PokemonAbility
.__table__
,
1706 order_by
=PokemonAbility
.slot
,
1708 Pokemon
.abilities
= relation(Ability
,
1709 secondary
=PokemonAbility
.__table__
,
1711 Pokemon
.id == PokemonAbility
.pokemon_id
,
1712 PokemonAbility
.is_dream
== False,
1714 order_by
=PokemonAbility
.slot
,
1716 Pokemon
.dream_ability
= relation(Ability
,
1717 secondary
=PokemonAbility
.__table__
,
1719 Pokemon
.id == PokemonAbility
.pokemon_id
,
1720 PokemonAbility
.is_dream
== True,
1724 Pokemon
.pokemon_color
= relation(PokemonColor
, backref
='pokemon')
1725 Pokemon
.color
= association_proxy('pokemon_color', 'name')
1726 Pokemon
.dex_numbers
= relation(PokemonDexNumber
, order_by
=PokemonDexNumber
.pokedex_id
.asc(), backref
='pokemon')
1727 Pokemon
.egg_groups
= relation(EggGroup
, secondary
=PokemonEggGroup
.__table__
,
1728 order_by
=PokemonEggGroup
.egg_group_id
,
1729 backref
=backref('pokemon', order_by
=Pokemon
.order
))
1730 Pokemon
.evolution_chain
= relation(EvolutionChain
, back_populates
='pokemon')
1731 Pokemon
.child_pokemon
= relation(Pokemon
,
1732 primaryjoin
=Pokemon
.id==PokemonEvolution
.from_pokemon_id
,
1733 secondary
=PokemonEvolution
.__table__
,
1734 secondaryjoin
=PokemonEvolution
.to_pokemon_id
==Pokemon
.id,
1735 backref
=backref('parent_pokemon', uselist
=False),
1737 Pokemon
.flavor_text
= relation(PokemonFlavorText
, order_by
=PokemonFlavorText
.version_id
.asc(), backref
='pokemon')
1738 Pokemon
.forms
= relation(PokemonForm
, primaryjoin
=Pokemon
.id==PokemonForm
.form_base_pokemon_id
,
1739 order_by
=(PokemonForm
.order
.asc(), PokemonForm
.identifier
.asc()))
1740 Pokemon
.default_form
= relation(PokemonForm
,
1741 primaryjoin
=and_(Pokemon
.id==PokemonForm
.form_base_pokemon_id
, PokemonForm
.is_default
==True),
1744 Pokemon
.pokemon_habitat
= relation(PokemonHabitat
, backref
='pokemon')
1745 Pokemon
.habitat
= association_proxy('pokemon_habitat', 'name')
1746 Pokemon
.items
= relation(PokemonItem
, backref
='pokemon')
1747 Pokemon
.generation
= relation(Generation
, backref
='pokemon')
1748 Pokemon
.shape
= relation(PokemonShape
, backref
='pokemon')
1749 Pokemon
.stats
= relation(PokemonStat
, backref
='pokemon', order_by
=PokemonStat
.stat_id
.asc())
1750 Pokemon
.types
= relation(Type
, secondary
=PokemonType
.__table__
,
1751 order_by
=PokemonType
.slot
.asc(),
1752 back_populates
='pokemon')
1754 PokemonDexNumber
.pokedex
= relation(Pokedex
)
1756 PokemonEvolution
.from_pokemon
= relation(Pokemon
,
1757 primaryjoin
=PokemonEvolution
.from_pokemon_id
==Pokemon
.id,
1758 backref
='child_evolutions',
1760 PokemonEvolution
.to_pokemon
= relation(Pokemon
,
1761 primaryjoin
=PokemonEvolution
.to_pokemon_id
==Pokemon
.id,
1762 backref
=backref('parent_evolution', uselist
=False),
1764 PokemonEvolution
.child_evolutions
= relation(PokemonEvolution
,
1765 primaryjoin
=PokemonEvolution
.from_pokemon_id
==PokemonEvolution
.to_pokemon_id
,
1766 foreign_keys
=[PokemonEvolution
.to_pokemon_id
],
1767 backref
=backref('parent_evolution',
1768 remote_side
=[PokemonEvolution
.from_pokemon_id
],
1772 PokemonEvolution
.trigger
= relation(EvolutionTrigger
, backref
='evolutions')
1773 PokemonEvolution
.trigger_item
= relation(Item
,
1774 primaryjoin
=PokemonEvolution
.trigger_item_id
==Item
.id,
1775 backref
='triggered_evolutions',
1777 PokemonEvolution
.held_item
= relation(Item
,
1778 primaryjoin
=PokemonEvolution
.held_item_id
==Item
.id,
1779 backref
='required_for_evolutions',
1781 PokemonEvolution
.location
= relation(Location
, backref
='triggered_evolutions')
1782 PokemonEvolution
.known_move
= relation(Move
, backref
='triggered_evolutions')
1783 PokemonEvolution
.party_pokemon
= relation(Pokemon
,
1784 primaryjoin
=PokemonEvolution
.party_pokemon_id
==Pokemon
.id,
1785 backref
='triggered_evolutions',
1787 PokemonEvolution
.trade_pokemon
= relation(Pokemon
,
1788 primaryjoin
=PokemonEvolution
.trade_pokemon_id
==Pokemon
.id,
1791 PokemonFlavorText
.version
= relation(Version
)
1793 PokemonForm
.form_base_pokemon
= relation(Pokemon
, primaryjoin
=PokemonForm
.form_base_pokemon_id
==Pokemon
.id)
1794 PokemonForm
.unique_pokemon
= relation(Pokemon
, backref
=backref('unique_form', uselist
=False),
1795 primaryjoin
=PokemonForm
.unique_pokemon_id
==Pokemon
.id)
1796 PokemonForm
.version_group
= relation(VersionGroup
)
1797 PokemonForm
.form_group
= association_proxy('form_base_pokemon', 'form_group')
1798 PokemonForm
.pokeathlon_stats
= relation(PokemonFormPokeathlonStat
,
1799 order_by
=PokemonFormPokeathlonStat
.pokeathlon_stat_id
,
1800 backref
='pokemon_form')
1802 PokemonFormGroup
.pokemon
= relation(Pokemon
, backref
=backref('form_group',
1805 PokemonFormPokeathlonStat
.pokeathlon_stat
= relation(PokeathlonStat
)
1807 PokemonItem
.item
= relation(Item
, backref
='pokemon')
1808 PokemonItem
.version
= relation(Version
)
1810 PokemonMove
.pokemon
= relation(Pokemon
, backref
='pokemon_moves')
1811 PokemonMove
.version_group
= relation(VersionGroup
)
1812 PokemonMove
.machine
= relation(Machine
, backref
='pokemon_moves',
1813 primaryjoin
=and_(Machine
.version_group_id
==PokemonMove
.version_group_id
,
1814 Machine
.move_id
==PokemonMove
.move_id
),
1815 foreign_keys
=[Machine
.version_group_id
, Machine
.move_id
],
1817 PokemonMove
.move
= relation(Move
, backref
='pokemon_moves')
1818 PokemonMove
.method
= relation(PokemonMoveMethod
)
1820 PokemonStat
.stat
= relation(Stat
)
1822 # This is technically a has-many; Generation.main_region_id -> Region.id
1823 Region
.generation
= relation(Generation
, uselist
=False)
1824 Region
.version_group_regions
= relation(VersionGroupRegion
, backref
='region',
1825 order_by
='VersionGroupRegion.version_group_id')
1826 Region
.version_groups
= association_proxy('version_group_regions', 'version_group')
1828 Stat
.damage_class
= relation(MoveDamageClass
, backref
='stats')
1830 StatHint
.stat
= relation(Stat
, backref
='hints')
1832 SuperContestCombo
.first
= relation(Move
, primaryjoin
=SuperContestCombo
.first_move_id
==Move
.id,
1833 backref
='super_contest_combo_first')
1834 SuperContestCombo
.second
= relation(Move
, primaryjoin
=SuperContestCombo
.second_move_id
==Move
.id,
1835 backref
='super_contest_combo_second')
1837 Type
.damage_efficacies
= relation(TypeEfficacy
,
1839 ==TypeEfficacy
.damage_type_id
,
1840 backref
='damage_type')
1841 Type
.target_efficacies
= relation(TypeEfficacy
,
1843 ==TypeEfficacy
.target_type_id
,
1844 backref
='target_type')
1846 Type
.generation
= relation(Generation
, backref
='types')
1847 Type
.damage_class
= relation(MoveDamageClass
, backref
='types')
1848 Type
.pokemon
= relation(Pokemon
, secondary
=PokemonType
.__table__
,
1849 order_by
=Pokemon
.order
,
1850 back_populates
='types')
1851 Type
.moves
= relation(Move
, back_populates
='type', order_by
=Move
.id)
1853 Version
.version_group
= relation(VersionGroup
, back_populates
='versions')
1854 Version
.generation
= association_proxy('version_group', 'generation')
1856 VersionGroup
.versions
= relation(Version
, order_by
=Version
.id, back_populates
='version_group')
1857 VersionGroup
.generation
= relation(Generation
, backref
='version_groups')
1858 VersionGroup
.version_group_regions
= relation(VersionGroupRegion
, backref
='version_group')
1859 VersionGroup
.regions
= association_proxy('version_group_regions', 'region')
1860 VersionGroup
.pokedex
= relation(Pokedex
, back_populates
='version_groups')
1863 ### Add text/prose tables
1865 default_lang
= u
'en'
1867 def create_translation_table(_table_name
, foreign_class
,
1868 _language_class
=Language
, **kwargs
):
1869 """Creates a table that represents some kind of data attached to the given
1870 foreign class, but translated across several languages. Returns the new
1871 table's mapped class.
1872 TODO give it a __table__ or __init__?
1874 `foreign_class` must have a `__singlename__`, currently only used to create
1875 the name of the foreign key column.
1876 TODO remove this requirement
1878 Also supports the notion of a default language, which is attached to the
1879 session. This is English by default, for historical and practical reasons.
1881 Usage looks like this:
1883 class Foo(Base): ...
1885 create_translation_table('foo_bars', Foo,
1889 # Now you can do the following:
1894 foo.name_map['en'] = "new name"
1895 del foo.name_map['en']
1897 q.options(joinedload(Foo.default_translation))
1898 q.options(joinedload(Foo.foo_bars))
1900 In the above example, the following attributes are added to Foo:
1902 - `foo_bars`, a relation to the new table. It uses a dict-based collection
1903 class, where the keys are language identifiers and the values are rows in
1905 - `foo_bars_local`, a relation to the row in the new table that matches the
1906 current default language.
1908 Note that these are distinct relations. Even though the former necessarily
1909 includes the latter, SQLAlchemy doesn't treat them as linked; loading one
1910 will not load the other. Modifying both within the same transaction has
1913 For each column provided, the following additional attributes are added to
1916 - `(column)_map`, an association proxy onto `foo_bars`.
1917 - `(column)`, an association proxy onto `foo_bars_local`.
1919 Pardon the naming disparity, but the grammar suffers otherwise.
1921 Modifying these directly is not likely to be a good idea.
1923 # n.b.: _language_class only exists for the sake of tests, which sometimes
1924 # want to create tables entirely separate from the pokedex metadata
1926 foreign_key_name
= foreign_class
.__singlename__
+ '_id'
1927 # A foreign key "language_id" will clash with the language_id we naturally
1928 # put in every table. Rename it something else
1929 if foreign_key_name
== 'language_id':
1930 # TODO change language_id below instead and rename this
1931 foreign_key_name
= 'lang_id'
1933 Translations
= type(_table_name
, (object,), {
1934 '_language_identifier': association_proxy('language', 'identifier'),
1937 # Create the table object
1938 table
= Table(_table_name
, foreign_class
.__table__
.metadata
,
1939 Column(foreign_key_name
, Integer
, ForeignKey(foreign_class
.id),
1940 primary_key
=True, nullable
=False),
1941 Column('language_id', Integer
, ForeignKey(_language_class
.id),
1942 primary_key
=True, nullable
=False),
1946 # Column objects have a _creation_order attribute in ascending order; use
1947 # this to get the (unordered) kwargs sorted correctly
1948 kwitems
= kwargs
.items()
1949 kwitems
.sort(key
=lambda kv
: kv
[1]._creation_order
)
1950 for name
, column
in kwitems
:
1952 table
.append_column(column
)
1954 # Construct ye mapper
1955 mapper(Translations
, table
, properties
={
1956 # TODO change to foreign_id
1957 'object_id': synonym(foreign_key_name
),
1958 # TODO change this as appropriate
1959 'language': relation(_language_class
,
1960 primaryjoin
=table
.c
.language_id
== _language_class
.id,
1963 # TODO does this need to join to the original table?
1966 # Add full-table relations to the original class
1968 class LanguageMapping(MappedCollection
):
1969 """Baby class that converts a language identifier key into an actual
1970 language object, allowing for `foo.bars['en'] = Translations(...)`.
1972 Needed for per-column association proxies to function as setters.
1974 @collection.internally_instrumented
1975 def __setitem__(self
, key
, value
, _sa_initiator
=None):
1977 raise NotImplementedError("Can't replace the whole row, sorry!")
1979 # Only do this nonsense if the value is a dangling object; if it's
1980 # in the db it already has its language_id
1981 if not object_session(value
):
1982 # This took quite some source-diving to find, but it oughta be
1983 # the object that actually owns this collection.
1984 obj
= collection_adapter(self
).owner_state
.obj()
1985 session
= object_session(obj
)
1986 value
.language
= session
.query(_language_class
) \
1987 .filter_by(identifier
=key
).one()
1989 super(LanguageMapping
, self
).__setitem__(key
, value
, _sa_initiator
)
1991 setattr(foreign_class
, _table_name
, relation(Translations
,
1992 primaryjoin
=foreign_class
.id == Translations
.object_id
,
1993 #collection_class=attribute_mapped_collection('_language_identifier'),
1994 collection_class
=partial(LanguageMapping
,
1995 lambda obj
: obj
._language_identifier
),
1999 # Class.foo_bars_local
2000 # This is a bit clever; it uses bindparam() to make the join clause
2001 # modifiable on the fly. db sessions know the current language identifier
2002 # populates the bindparam.
2003 local_relation_name
= _table_name
+ '_local'
2004 setattr(foreign_class
, local_relation_name
, relation(Translations
,
2006 foreign_class
.id == Translations
.object_id
,
2007 Translations
._language_identifier
==
2008 bindparam('_default_language', required
=True),
2015 # Add per-column proxies to the original class
2016 for name
, column
in kwitems
:
2017 # TODO should these proxies be mutable?
2019 # Class.(column) -- accessor for the default language's value
2020 setattr(foreign_class
, name
,
2021 association_proxy(local_relation_name
, name
))
2023 # Class.(column)_map -- accessor for the language dict
2024 # Need a custom creator since Translations doesn't have an init, and
2025 # these are passed as *args anyway
2026 def creator(language_code
, value
):
2027 row
= Translations()
2028 setattr(row
, name
, value
)
2030 setattr(foreign_class
, name
+ '_map',
2031 association_proxy(_table_name
, name
, creator
=creator
))
2036 def makeTextTable(foreign_table_class
, table_suffix_plural
, table_suffix_singular
, columns
, lazy
, Language
=Language
):
2037 # With "Language", we'd have two language_id. So, rename one to 'lang'
2038 foreign_key_name
= foreign_table_class
.__singlename__
2039 if foreign_key_name
== 'language':
2040 foreign_key_name
= 'lang'
2042 table_name
= foreign_table_class
.__singlename__
+ '_' + table_suffix_plural
2044 class TranslatedStringsTable(object):
2045 __tablename__
= table_name
2046 _attrname
= table_suffix_plural
2047 _language_identifier
= association_proxy('language', 'identifier')
2049 for column_name
, column_name_plural
, column
in columns
:
2050 column
.name
= column_name
2051 if not column
.nullable
:
2052 # A Python side default value, so that the strings can be set
2053 # one by one without the DB complaining about missing values
2054 column
.default
= ColumnDefault(u
'')
2056 table
= Table(table_name
, foreign_table_class
.__table__
.metadata
,
2057 Column(foreign_key_name
+ '_id', Integer
, ForeignKey(foreign_table_class
.id),
2058 primary_key
=True, nullable
=False),
2059 Column('language_id', Integer
, ForeignKey(Language
.id),
2060 primary_key
=True, index
=True, nullable
=False),
2061 *(column
for name
, plural
, column
in columns
)
2064 mapper(TranslatedStringsTable
, table
,
2066 "object_id": synonym(foreign_key_name
+ '_id'),
2067 "language": relation(Language
,
2068 primaryjoin
=table
.c
.language_id
== Language
.id,
2070 foreign_key_name
: relation(foreign_table_class
,
2071 primaryjoin
=(foreign_table_class
.id == table
.c
[foreign_key_name
+ "_id"]),
2072 backref
=backref(table_suffix_plural
,
2073 collection_class
=attribute_mapped_collection('_language_identifier'),
2080 # The relation to the object
2081 TranslatedStringsTable
.object = getattr(TranslatedStringsTable
, foreign_key_name
)
2083 # Link the tables themselves, so we can get them if needed
2084 TranslatedStringsTable
.foreign_table_class
= foreign_table_class
2085 setattr(foreign_table_class
, table_suffix_singular
+ '_table', TranslatedStringsTable
)
2087 for column_name
, column_name_plural
, column
in columns
:
2088 # Provide a property with all the names, and an English accessor
2089 # for backwards compatibility
2090 def text_string_creator(language_code
, string
):
2091 row
= TranslatedStringsTable()
2092 row
._language_identifier
= language_code
2093 setattr(row
, column_name
, string
)
2096 setattr(foreign_table_class
, column_name_plural
,
2097 association_proxy(table_suffix_plural
, column_name
, creator
=text_string_creator
))
2098 setattr(foreign_table_class
, column_name
, DefaultLangProperty(column_name_plural
))
2100 if column_name
== 'name':
2101 foreign_table_class
.name_table
= TranslatedStringsTable
2104 return TranslatedStringsTable
2106 class DefaultLangProperty(object):
2107 def __init__(self
, column_name
):
2108 self
.column_name
= column_name
2110 def __get__(self
, instance
, cls
):
2112 return getattr(instance
, self
.column_name
)[default_lang
]
2114 # TODO I think this is kind of broken
2115 return getattr(cls
, self
.column_name
)[default_lang
]
2117 def __set__(self
, instance
, value
):
2118 getattr(instance
, self
.colname
)[default_lang
] = value
2120 def __delete__(self
, instance
):
2121 del getattr(instance
, self
.colname
)[default_lang
]
2123 for table
in list(table_classes
):
2124 # Find all the language-specific columns, keeping them in the order they
2127 for colname
in dir(table
):
2128 column
= getattr(table
, colname
)
2129 if isinstance(column
, LanguageSpecificColumn
):
2130 all_columns
.append((colname
, column
))
2131 delattr(table
, colname
)
2132 all_columns
.sort(key
=lambda pair
: pair
[1].order
)
2134 # Break them into text and prose columns
2137 for colname
, column
in all_columns
:
2138 spec
= colname
, column
.plural
, column
.makeSAColumn()
2139 if isinstance(column
, TextColumn
):
2140 text_columns
.append(spec
)
2141 elif isinstance(column
, ProseColumn
):
2142 prose_columns
.append(spec
)
2144 if (text_columns
or prose_columns
) and issubclass(table
, LanguageSpecific
):
2145 raise AssertionError("Language-specific table %s shouldn't have explicit language-specific columns" % table
)
2148 string_table
= makeTextTable(table
, 'texts', 'text', text_columns
, lazy
=False)
2150 string_table
= makeTextTable(table
, 'prose', 'prose', prose_columns
, lazy
='select')
2152 ### Add language relations
2153 for table
in list(table_classes
):
2154 if issubclass(table
, LanguageSpecific
):
2155 table
.language
= relation(Language
, primaryjoin
=table
.language_id
== Language
.id)
2157 Move
.effect
= DefaultLangProperty('effects')
2158 Move
.effects
= markdown
.MoveEffectsProperty('effect')
2159 Move
.short_effect
= DefaultLangProperty('short_effects')
2160 Move
.short_effects
= markdown
.MoveEffectsProperty('short_effect')
2162 MoveChangelog
.effect
= DefaultLangProperty('effects')
2163 MoveChangelog
.effects
= markdown
.MoveEffectsProperty('effect')
2164 MoveChangelog
.short_effect
= DefaultLangProperty('short_effects')
2165 MoveChangelog
.short_effects
= markdown
.MoveEffectsProperty('short_effect')