Merge branch 'encukou'

This commit is contained in:
Eevee 2011-04-01 17:10:13 -07:00
commit 42a3989dc6
10 changed files with 245 additions and 225 deletions

View file

@ -0,0 +1 @@
item_id,local_language_id,flavor_summary
1 item_id local_language_id flavor_summary

View file

@ -8,3 +8,4 @@ language_id,local_language_id,name
7,9,Spanish 7,9,Spanish
8,9,Italian 8,9,Italian
9,9,English 9,9,English
10,9,Czech

1 language_id local_language_id name
8 7 9 Spanish
9 8 9 Italian
10 9 9 English
11 10 9 Czech

View file

@ -8,3 +8,4 @@ id,iso639,iso3166,identifier,official,order
7,es,es,es,1, 7,es,es,es,1,
8,it,it,it,1, 8,it,it,it,1,
9,en,us,en,1,0 9,en,us,en,1,0
10,cs,cz,cs,0,

1 id iso639 iso3166 identifier official order
8 7 es es es 1
9 8 it it it 1
10 9 en us en 1 0
11 10 cs cz cs 0

View file

@ -0,0 +1 @@
move_id,local_language_id,flavor_summary
1 move_id local_language_id flavor_summary

View file

@ -0,0 +1 @@
pokemon_id,local_language_id,flavor_summary
1 pokemon_id local_language_id flavor_summary

View file

@ -174,14 +174,10 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
if not safe and session.connection().dialect.name == 'postgresql': if not safe and session.connection().dialect.name == 'postgresql':
""" """
Postgres' CSV dialect is nearly the same as ours, except that it Postgres' CSV dialect works with our data, if we mark the not-null
treats completely empty values as NULL, and empty quoted columns with FORCE NOT NULL.
strings ("") as an empty strings. COPY is only allowed for DB superusers. If you're not one, use safe
Pokedex dump does not quote empty strings. So, both empty strings loading (pokedex load -S).
and NULLs are read in as NULL.
For an empty string in a NOT NULL column, the load will fail, and
load will fall back to the cross-backend row-by-row loading. And in
nullable columns, we already load empty stings as NULL.
""" """
session.commit() session.commit()
not_null_cols = [c for c in column_names if not table_obj.c[c].nullable] not_null_cols = [c for c in column_names if not table_obj.c[c].nullable]

View file

@ -77,9 +77,11 @@ def create_translation_table(_table_name, foreign_class, relation_name,
# Create the table object # Create the table object
table = Table(_table_name, foreign_class.__table__.metadata, table = Table(_table_name, foreign_class.__table__.metadata,
Column(foreign_key_name, Integer, ForeignKey(foreign_class.id), Column(foreign_key_name, Integer, ForeignKey(foreign_class.id),
primary_key=True, nullable=False), primary_key=True, nullable=False,
info=dict(description="ID of the %s these texts relate to" % foreign_class.__singlename__)),
Column('local_language_id', Integer, ForeignKey(language_class.id), Column('local_language_id', Integer, ForeignKey(language_class.id),
primary_key=True, nullable=False), primary_key=True, nullable=False,
info=dict(description="Language these texts are in")),
) )
Translations.__table__ = table Translations.__table__ = table
@ -145,6 +147,9 @@ def create_translation_table(_table_name, foreign_class, relation_name,
setattr(foreign_class, name + '_map', setattr(foreign_class, name + '_map',
association_proxy(relation_name, name, creator=creator)) association_proxy(relation_name, name, creator=creator))
# Add to the list of translation classes
foreign_class.translation_classes.append(Translations)
# Done # Done
return Translations return Translations

View file

@ -15,6 +15,8 @@ Columns have a info dictionary with these keys:
- identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended - identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
for translation. for translation.
- latex: A formula in LaTeX syntax. - latex: A formula in LaTeX syntax.
- ripped: True for text that has been ripped from the games, and can be ripped
again for new versions or languages
See `pokedex.db.multilang` for how localizable text columns work. The session See `pokedex.db.multilang` for how localizable text columns work. The session
classes in that module can be used to change the default language. classes in that module can be used to change the default language.
@ -25,7 +27,7 @@ import collections
from functools import partial from functools import partial
from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import backref, relation from sqlalchemy.orm import backref, relation
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
@ -60,8 +62,16 @@ class TableSuperclass(object):
def __str__(self): def __str__(self):
return unicode(self).encode('utf8') return unicode(self).encode('utf8')
mapped_classes = []
class TableMetaclass(DeclarativeMeta):
def __init__(cls, name, bases, attrs):
super(TableMetaclass, cls).__init__(name, bases, attrs)
if hasattr(cls, '__tablename__'):
mapped_classes.append(cls)
cls.translation_classes = []
metadata = MetaData() metadata = MetaData()
TableBase = declarative_base(metadata=metadata, cls=TableSuperclass) TableBase = declarative_base(metadata=metadata, cls=TableSuperclass, metaclass=TableMetaclass)
### Need Language first, to create the partial() below ### Need Language first, to create the partial() below
@ -108,7 +118,7 @@ class Ability(TableBase):
create_translation_table('ability_names', Ability, 'names', create_translation_table('ability_names', Ability, 'names',
relation_lazy='joined', relation_lazy='joined',
name = Column(Unicode(24), nullable=False, index=True, name = Column(Unicode(24), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True)), info=dict(description="The name", format='plaintext', official=True, ripped=True)),
) )
create_translation_table('ability_prose', Ability, 'prose', create_translation_table('ability_prose', Ability, 'prose',
effect = Column(markdown.MarkdownColumn(5120), nullable=False, effect = Column(markdown.MarkdownColumn(5120), nullable=False,
@ -351,22 +361,6 @@ class EncounterConditionValueMap(TableBase):
encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False, encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="The ID of the encounter condition value")) info=dict(description="The ID of the encounter condition value"))
class EncounterTerrain(TableBase):
u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
"""
__tablename__ = 'encounter_terrain'
__singlename__ = __tablename__
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for the terrain"))
identifier = Column(Unicode(64), nullable=False,
info=dict(description="An identifier", format='identifier'))
create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
name = Column(Unicode(64), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=False)),
)
class EncounterSlot(TableBase): class EncounterSlot(TableBase):
u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity. u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
@ -386,6 +380,22 @@ class EncounterSlot(TableBase):
rarity = Column(Integer, nullable=False, rarity = Column(Integer, nullable=False,
info=dict(description="The chance of the encounter as a percentage")) info=dict(description="The chance of the encounter as a percentage"))
class EncounterTerrain(TableBase):
u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
"""
__tablename__ = 'encounter_terrain'
__singlename__ = __tablename__
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A unique ID for the terrain"))
identifier = Column(Unicode(64), nullable=False,
info=dict(description="An identifier", format='identifier'))
create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
name = Column(Unicode(64), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=False)),
)
class EvolutionChain(TableBase): class EvolutionChain(TableBase):
u"""A family of Pokémon that are linked by evolution u"""A family of Pokémon that are linked by evolution
""" """
@ -487,7 +497,7 @@ class Item(TableBase):
create_translation_table('item_names', Item, 'names', create_translation_table('item_names', Item, 'names',
relation_lazy='joined', relation_lazy='joined',
name = Column(Unicode(20), nullable=False, index=True, name = Column(Unicode(20), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True)), info=dict(description="The name", format='plaintext', official=True, ripped=True)),
) )
create_translation_table('item_prose', Item, 'prose', create_translation_table('item_prose', Item, 'prose',
short_effect = Column(Unicode(256), nullable=False, short_effect = Column(Unicode(256), nullable=False,
@ -495,6 +505,10 @@ create_translation_table('item_prose', Item, 'prose',
effect = Column(markdown.MarkdownColumn(5120), nullable=False, effect = Column(markdown.MarkdownColumn(5120), nullable=False,
info=dict(description=u"Detailed description of the item's effect.", format='markdown')), info=dict(description=u"Detailed description of the item's effect.", format='markdown')),
) )
create_translation_table('item_flavor_summaries', Item, 'flavor_summaries',
flavor_summary = Column(Unicode(512), nullable=True,
info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext', ripped=True)),
)
class ItemCategory(TableBase): class ItemCategory(TableBase):
u"""An item category u"""An item category
@ -546,6 +560,7 @@ class ItemFlavorText(TableBase):
""" """
__tablename__ = 'item_flavor_text' __tablename__ = 'item_flavor_text'
__singlename__ = 'item_flavor_text' __singlename__ = 'item_flavor_text'
summary_column = Item.flavor_summaries_table, 'flavor_summary'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False, item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
info=dict(description="The ID of the item")) info=dict(description="The ID of the item"))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False, version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
@ -675,6 +690,52 @@ class Machine(TableBase):
""" """
return self.machine_number >= 100 return self.machine_number >= 100
class Move(TableBase):
u"""A Move: technique or attack a Pokémon can learn to use
"""
__tablename__ = 'moves'
__singlename__ = 'move'
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(24), nullable=False,
info=dict(description="An identifier", format='identifier'))
generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
info=dict(description="ID of the generation this move first appeared in"))
type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
info=dict(description="ID of the move's elemental type"))
power = Column(SmallInteger, nullable=False,
info=dict(description="Base power of the move"))
pp = Column(SmallInteger, nullable=True,
info=dict(description="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
accuracy = Column(SmallInteger, nullable=True,
info=dict(description="Accuracy of the move; NULL means it never misses"))
priority = Column(SmallInteger, nullable=False,
info=dict(description="The move's priority bracket"))
target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False,
info=dict(description="ID of the target (range) of the move"))
damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
info=dict(description="ID of the damage class (physical/special) of the move"))
effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
info=dict(description="ID of the move's effect"))
effect_chance = Column(Integer, nullable=True,
info=dict(description="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True,
info=dict(description="ID of the move's Contest type (e.g. cool or smart)"))
contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True,
info=dict(description="ID of the move's Contest effect"))
super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
info=dict(description="ID of the move's Super Contest effect"))
create_translation_table('move_names', Move, 'names',
relation_lazy='joined',
name = Column(Unicode(24), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True, ripped=True))
)
create_translation_table('move_flavor_summaries', Move, 'flavor_summaries',
flavor_summary = Column(Unicode(512), nullable=True,
info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext', ripped=True)),
)
class MoveBattleStyle(TableBase): class MoveBattleStyle(TableBase):
u"""A battle style of a move""" # XXX: Explain better u"""A battle style of a move""" # XXX: Explain better
__tablename__ = 'move_battle_styles' __tablename__ = 'move_battle_styles'
@ -690,33 +751,26 @@ create_translation_table('move_battle_style_prose', MoveBattleStyle, 'prose',
info=dict(description="The name", format='plaintext', official=False)), info=dict(description="The name", format='plaintext', official=False)),
) )
class MoveEffectCategory(TableBase): class MoveChangelog(TableBase):
u"""Category of a move effect """History of changes to moves across main game versions."""
""" __tablename__ = 'move_changelog'
__tablename__ = 'move_effect_categories' __singlename__ = 'move_changelog'
__singlename__ = 'move_effect_category' move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
id = Column(Integer, primary_key=True, nullable=False, info=dict(description="ID of the move that changed"))
info=dict(description="A numeric ID")) changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
identifier = Column(Unicode(64), nullable=False, info=dict(description="ID of the version group in which the move changed"))
info=dict(description="An identifier", format='identifier')) type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
can_affect_user = Column(Boolean, nullable=False, info=dict(description="Prior type of the move, or NULL if unchanged"))
info=dict(description="Set if the user can be affected")) power = Column(SmallInteger, nullable=True,
info=dict(description="Prior base power of the move, or NULL if unchanged"))
create_translation_table('move_effect_category_prose', MoveEffectCategory, 'prose', pp = Column(SmallInteger, nullable=True,
name = Column(Unicode(64), nullable=False, index=True, info=dict(description="Prior base PP of the move, or NULL if unchanged"))
info=dict(description="The name", format='plaintext', official=False)), accuracy = Column(SmallInteger, nullable=True,
) info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=True,
class MoveEffectCategoryMap(TableBase): info=dict(description="Prior ID of the effect, or NULL if unchanged"))
u"""Maps a move effect category to a move effect effect_chance = Column(Integer, nullable=True,
""" info=dict(description="Prior effect chance, or NULL if unchanged"))
__tablename__ = 'move_effect_category_map'
move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
info=dict(description="ID of the move effect"))
move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
info=dict(description="ID of the category"))
affects_user = Column(Boolean, primary_key=True, nullable=False,
info=dict(description="Set if the user is affected"))
class MoveDamageClass(TableBase): class MoveDamageClass(TableBase):
u"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging. u"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging.
@ -751,6 +805,34 @@ create_translation_table('move_effect_prose', MoveEffect, 'prose',
info=dict(description="A detailed description of the effect", format='plaintext')), info=dict(description="A detailed description of the effect", format='plaintext')),
) )
class MoveEffectCategory(TableBase):
u"""Category of a move effect
"""
__tablename__ = 'move_effect_categories'
__singlename__ = 'move_effect_category'
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(64), nullable=False,
info=dict(description="An identifier", format='identifier'))
can_affect_user = Column(Boolean, nullable=False,
info=dict(description="Set if the user can be affected"))
create_translation_table('move_effect_category_prose', MoveEffectCategory, 'prose',
name = Column(Unicode(64), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=False)),
)
class MoveEffectCategoryMap(TableBase):
u"""Maps a move effect category to a move effect
"""
__tablename__ = 'move_effect_category_map'
move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
info=dict(description="ID of the move effect"))
move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
info=dict(description="ID of the category"))
affects_user = Column(Boolean, primary_key=True, nullable=False,
info=dict(description="Set if the user is affected"))
class MoveEffectChangelog(TableBase): class MoveEffectChangelog(TableBase):
"""History of changes to move effects across main game versions.""" """History of changes to move effects across main game versions."""
__tablename__ = 'move_effect_changelog' __tablename__ = 'move_effect_changelog'
@ -805,6 +887,7 @@ class MoveFlavorText(TableBase):
u"""In-game description of a move u"""In-game description of a move
""" """
__tablename__ = 'move_flavor_text' __tablename__ = 'move_flavor_text'
summary_column = Move.flavor_summaries_table, 'flavor_summary'
move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False, move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description="ID of the move")) info=dict(description="ID of the move"))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False, version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
@ -871,7 +954,7 @@ class MoveMetaCategory(TableBase):
create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose', create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
relation_lazy='joined', relation_lazy='joined',
description = Column(Unicode(64), nullable=False, description = Column(Unicode(64), nullable=False,
info=dict(description="A description of the category")), info=dict(description="A description of the category", format="plaintext", official=False)),
) )
class MoveMetaStatChange(TableBase): class MoveMetaStatChange(TableBase):
@ -902,70 +985,6 @@ create_translation_table('move_target_prose', MoveTarget, 'prose',
info=dict(description="A description", format='plaintext')), info=dict(description="A description", format='plaintext')),
) )
class Move(TableBase):
u"""A Move: technique or attack a Pokémon can learn to use
"""
__tablename__ = 'moves'
__singlename__ = 'move'
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description="A numeric ID"))
identifier = Column(Unicode(24), nullable=False,
info=dict(description="An identifier", format='identifier'))
generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
info=dict(description="ID of the generation this move first appeared in"))
type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
info=dict(description="ID of the move's elemental type"))
power = Column(SmallInteger, nullable=False,
info=dict(description="Base power of the move"))
pp = Column(SmallInteger, nullable=True,
info=dict(description="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
accuracy = Column(SmallInteger, nullable=True,
info=dict(description="Accuracy of the move; NULL means it never misses"))
priority = Column(SmallInteger, nullable=False,
info=dict(description="The move's priority bracket"))
target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False,
info=dict(description="ID of the target (range) of the move"))
damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
info=dict(description="ID of the damage class (physical/special) of the move"))
effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
info=dict(description="ID of the move's effect"))
effect_chance = Column(Integer, nullable=True,
info=dict(description="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True,
info=dict(description="ID of the move's Contest type (e.g. cool or smart)"))
contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True,
info=dict(description="ID of the move's Contest effect"))
super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
info=dict(description="ID of the move's Super Contest effect"))
create_translation_table('move_names', Move, 'names',
relation_lazy='joined',
name = Column(Unicode(24), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True))
)
class MoveChangelog(TableBase):
"""History of changes to moves across main game versions."""
__tablename__ = 'move_changelog'
__singlename__ = 'move_changelog'
move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
info=dict(description="ID of the move that changed"))
changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
info=dict(description="ID of the version group in which the move changed"))
type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
info=dict(description="Prior type of the move, or NULL if unchanged"))
power = Column(SmallInteger, nullable=True,
info=dict(description="Prior base power of the move, or NULL if unchanged"))
pp = Column(SmallInteger, nullable=True,
info=dict(description="Prior base PP of the move, or NULL if unchanged"))
accuracy = Column(SmallInteger, nullable=True,
info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=True,
info=dict(description="Prior ID of the effect, or NULL if unchanged"))
effect_chance = Column(Integer, nullable=True,
info=dict(description="Prior effect chance, or NULL if unchanged"))
class Nature(TableBase): class Nature(TableBase):
u"""A nature a Pokémon can have, such as Calm or Brave u"""A nature a Pokémon can have, such as Calm or Brave
""" """
@ -994,7 +1013,7 @@ class Nature(TableBase):
create_translation_table('nature_names', Nature, 'names', create_translation_table('nature_names', Nature, 'names',
relation_lazy='joined', relation_lazy='joined',
name = Column(Unicode(8), nullable=False, index=True, name = Column(Unicode(8), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True)), info=dict(description="The name", format='plaintext', official=True, ripped=True)),
) )
class NatureBattleStylePreference(TableBase): class NatureBattleStylePreference(TableBase):
@ -1184,11 +1203,15 @@ class Pokemon(TableBase):
create_translation_table('pokemon_names', Pokemon, 'names', create_translation_table('pokemon_names', Pokemon, 'names',
relation_lazy='joined', relation_lazy='joined',
name = Column(Unicode(20), nullable=False, index=True, name = Column(Unicode(20), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True)), info=dict(description="The name", format='plaintext', official=True, ripped=True)),
species = Column(Unicode(16), nullable=False, species = Column(Unicode(16), nullable=False,
info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"', info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
official=True, format='plaintext')), official=True, format='plaintext')),
) )
create_translation_table('pokemon_flavor_summaries', Pokemon, 'flavor_summaries',
flavor_summary = Column(Unicode(512), nullable=True,
info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext', ripped=True)),
)
class PokemonAbility(TableBase): class PokemonAbility(TableBase):
u"""Maps an ability to a Pokémon that can have it u"""Maps an ability to a Pokémon that can have it
@ -1284,6 +1307,7 @@ class PokemonFlavorText(TableBase):
u"""In-game Pokédex descrption of a Pokémon. u"""In-game Pokédex descrption of a Pokémon.
""" """
__tablename__ = 'pokemon_flavor_text' __tablename__ = 'pokemon_flavor_text'
summary_column = Pokemon.flavor_summaries_table, 'flavor_summary'
pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False, pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description=u"ID of the Pokémon")) info=dict(description=u"ID of the Pokémon"))
version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False, version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
@ -1291,7 +1315,7 @@ class PokemonFlavorText(TableBase):
language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
info=dict(description="The language")) info=dict(description="The language"))
flavor_text = Column(Unicode(255), nullable=False, flavor_text = Column(Unicode(255), nullable=False,
info=dict(description=u"ID of the version that has this flavor text", official=True, format='gametext')) info=dict(description=u"The flavor text", official=True, format='gametext'))
class PokemonForm(TableBase): class PokemonForm(TableBase):
u"""An individual form of a Pokémon. u"""An individual form of a Pokémon.
@ -1383,6 +1407,17 @@ class PokemonFormPokeathlonStat(TableBase):
maximum_stat = Column(Integer, nullable=False, autoincrement=False, maximum_stat = Column(Integer, nullable=False, autoincrement=False,
info=dict(description=u'The maximum value for this stat for this Pokémon form.')) info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
class PokemonGameIndex(TableBase):
u"""The number of a Pokémon a game uses internally
"""
__tablename__ = 'pokemon_game_indices'
pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
info=dict(description=u"Database ID of the Pokémon"))
generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
info=dict(description=u"Database ID of the generation"))
game_index = Column(Integer, nullable=False,
info=dict(description=u"Internal ID the generation's games use for the Pokémon"))
class PokemonHabitat(TableBase): class PokemonHabitat(TableBase):
u"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex u"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex
""" """
@ -1399,17 +1434,6 @@ create_translation_table('pokemon_habitat_names', PokemonHabitat, 'names',
info=dict(description="The name", format='plaintext', official=True)), info=dict(description="The name", format='plaintext', official=True)),
) )
class PokemonGameIndex(TableBase):
u"""The number of a Pokémon a game uses internally
"""
__tablename__ = 'pokemon_game_indices'
pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
info=dict(description=u"Database ID of the Pokémon"))
generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
info=dict(description=u"Database ID of the generation"))
game_index = Column(Integer, nullable=False,
info=dict(description=u"Internal ID the generation's games use for the Pokémon"))
class PokemonItem(TableBase): class PokemonItem(TableBase):
u"""Record of an item a Pokémon can hold in the wild u"""Record of an item a Pokémon can hold in the wild
""" """
@ -1463,7 +1487,6 @@ create_translation_table('pokemon_move_method_prose', PokemonMoveMethod, 'prose'
info=dict(description=u"A detailed description of how the method works", format='plaintext')), info=dict(description=u"A detailed description of how the method works", format='plaintext')),
) )
class PokemonShape(TableBase): class PokemonShape(TableBase):
u"""The shape of a Pokémon's body, as used in generation IV Pokédexes. u"""The shape of a Pokémon's body, as used in generation IV Pokédexes.
""" """
@ -1585,19 +1608,6 @@ create_translation_table('super_contest_effect_prose', SuperContestEffect, 'pros
info=dict(description=u"A description of the effect.", format='plaintext', official=True)), info=dict(description=u"A description of the effect.", format='plaintext', official=True)),
) )
class TypeEfficacy(TableBase):
u"""The damage multiplier used when a move of a particular type damages a
Pokémon of a particular other type.
"""
__tablename__ = 'type_efficacy'
damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description=u"The ID of the damaging type."))
target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description=u"The ID of the defending Pokémon's type."))
damage_factor = Column(Integer, nullable=False,
info=dict(description=u"The multiplier, as a percentage of damage inflicted."))
class Type(TableBase): class Type(TableBase):
u"""Any of the elemental types Pokémon and moves can have.""" u"""Any of the elemental types Pokémon and moves can have."""
__tablename__ = 'types' __tablename__ = 'types'
@ -1617,6 +1627,35 @@ create_translation_table('type_names', Type, 'names',
info=dict(description="The name", format='plaintext', official=True)), info=dict(description="The name", format='plaintext', official=True)),
) )
class TypeEfficacy(TableBase):
u"""The damage multiplier used when a move of a particular type damages a
Pokémon of a particular other type.
"""
__tablename__ = 'type_efficacy'
damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description=u"The ID of the damaging type."))
target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
info=dict(description=u"The ID of the defending Pokémon's type."))
damage_factor = Column(Integer, nullable=False,
info=dict(description=u"The multiplier, as a percentage of damage inflicted."))
class Version(TableBase):
u"""An individual main-series Pokémon game."""
__tablename__ = 'versions'
__singlename__ = 'version'
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A unique ID for this version."))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
info=dict(description=u"The ID of the version group this game belongs to."))
identifier = Column(Unicode(32), nullable=False,
info=dict(description=u'And identifier', format='identifier'))
create_translation_table('version_names', Version, 'names',
relation_lazy='joined',
name = Column(Unicode(32), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True)),
)
class VersionGroup(TableBase): class VersionGroup(TableBase):
u"""A group of versions, containing either two paired versions (such as Red u"""A group of versions, containing either two paired versions (such as Red
and Blue) or a single game (such as Yellow.) and Blue) or a single game (such as Yellow.)
@ -1637,24 +1676,6 @@ class VersionGroupRegion(TableBase):
region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False, region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
info=dict(description=u"The ID of the region.")) info=dict(description=u"The ID of the region."))
class Version(TableBase):
u"""An individual main-series Pokémon game."""
__tablename__ = 'versions'
__singlename__ = 'version'
id = Column(Integer, primary_key=True, nullable=False,
info=dict(description=u"A unique ID for this version."))
version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
info=dict(description=u"The ID of the version group this game belongs to."))
identifier = Column(Unicode(32), nullable=False,
info=dict(description=u'And identifier', format='identifier'))
create_translation_table('version_names', Version, 'names',
relation_lazy='joined',
name = Column(Unicode(32), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True)),
)
### Relations down here, to avoid ordering problems ### Relations down here, to avoid ordering problems
Ability.changelog = relation(AbilityChangelog, Ability.changelog = relation(AbilityChangelog,
order_by=AbilityChangelog.changed_in_version_group_id.desc(), order_by=AbilityChangelog.changed_in_version_group_id.desc(),

View file

@ -23,9 +23,19 @@ def test_variable_names():
classname = table.__name__ classname = table.__name__
if classname and varname[0].isupper(): if classname and varname[0].isupper():
assert varname == classname, '%s refers to %s' % (varname, classname) assert varname == classname, '%s refers to %s' % (varname, classname)
for table in tables.table_classes: for table in tables.mapped_classes:
assert getattr(tables, table.__name__) is table assert getattr(tables, table.__name__) is table
def test_class_order():
"""The declarative classes should be defined in alphabetical order.
Except for Language which should be first.
"""
class_names = [table.__name__ for table in tables.mapped_classes]
def key(name):
return name != 'Language', name
print [(a,b) for (a,b) in zip(class_names, sorted(class_names, key=key)) if a!=b]
assert class_names == sorted(class_names, key=key)
def test_i18n_table_creation(): def test_i18n_table_creation():
"""Creates and manipulates a magical i18n table, completely independent of """Creates and manipulates a magical i18n table, completely independent of
the existing schema and data. Makes sure that the expected behavior of the the existing schema and data. Makes sure that the expected behavior of the
@ -46,8 +56,9 @@ def test_i18n_table_creation():
__tablename__ = 'foos' __tablename__ = 'foos'
__singlename__ = 'foo' __singlename__ = 'foo'
id = Column(Integer, primary_key=True, nullable=False) id = Column(Integer, primary_key=True, nullable=False)
translation_classes = []
FooText = create_translation_table('foo_text', Foo, FooText = create_translation_table('foo_text', Foo, 'texts',
language_class=Language, language_class=Language,
name = Column(String(100)), name = Column(String(100)),
) )
@ -79,14 +90,14 @@ def test_i18n_table_creation():
# Give our foo some names, as directly as possible # Give our foo some names, as directly as possible
foo_text = FooText() foo_text = FooText()
foo_text.object_id = foo.id foo_text.foreign_id = foo.id
foo_text.language_id = lang_en.id foo_text.local_language_id = lang_en.id
foo_text.name = 'english' foo_text.name = 'english'
sess.add(foo_text) sess.add(foo_text)
foo_text = FooText() foo_text = FooText()
foo_text.object_id = foo.id foo_text.foo_id = foo.id
foo_text.language_id = lang_jp.id foo_text.local_language_id = lang_jp.id
foo_text.name = 'nihongo' foo_text.name = 'nihongo'
sess.add(foo_text) sess.add(foo_text)
@ -116,7 +127,7 @@ def test_i18n_table_creation():
# THIS SHOULD WORK SOMEDAY # THIS SHOULD WORK SOMEDAY
# .options(joinedload(Foo.name)) \ # .options(joinedload(Foo.name)) \
foo = sess.query(Foo) \ foo = sess.query(Foo) \
.options(joinedload(Foo.foo_text_local)) \ .options(joinedload(Foo.texts_local)) \
.one() .one()
assert foo.name == 'english' assert foo.name == 'english'
@ -127,7 +138,7 @@ def test_i18n_table_creation():
# THIS SHOULD ALSO WORK SOMEDAY # THIS SHOULD ALSO WORK SOMEDAY
# .options(joinedload(Foo.name_map)) \ # .options(joinedload(Foo.name_map)) \
foo = sess.query(Foo) \ foo = sess.query(Foo) \
.options(joinedload(Foo.foo_text)) \ .options(joinedload(Foo.texts)) \
.one() .one()
assert foo.name_map[lang_en] == 'english' assert foo.name_map[lang_en] == 'english'
@ -152,15 +163,19 @@ def test_texts():
Mostly protects against copy/paste oversights and rebase hiccups. Mostly protects against copy/paste oversights and rebase hiccups.
If there's a reason to relax the tests, do it If there's a reason to relax the tests, do it
""" """
for table in sorted(tables.table_classes, key=lambda t: t.__name__): classes = []
if issubclass(table, tables.LanguageSpecific): for cls in tables.mapped_classes:
classes.append(cls)
classes += cls.translation_classes
for cls in classes:
if hasattr(cls, 'local_language') or hasattr(cls, 'language'):
good_formats = 'markdown plaintext gametext'.split() good_formats = 'markdown plaintext gametext'.split()
assert_text = '%s is language-specific' assert_text = '%s is language-specific'
else: else:
good_formats = 'identifier latex'.split() good_formats = 'identifier latex'.split()
assert_text = '%s is not language-specific' assert_text = '%s is not language-specific'
mapper = class_mapper(table) columns = sorted(cls.__table__.c, key=lambda c: c.name)
for column in sorted(mapper.c, key=lambda c: c.name): for column in columns:
format = column.info.get('format', None) format = column.info.get('format', None)
if format is not None: if format is not None:
if format not in good_formats: if format not in good_formats:
@ -185,11 +200,8 @@ def test_identifiers_with_names():
...have either names or identifiers. ...have either names or identifiers.
""" """
for table in sorted(tables.table_classes, key=lambda t: t.__name__): for table in sorted(tables.mapped_classes, key=lambda t: t.__name__):
if issubclass(table, tables.Named): if hasattr(table, 'name'):
assert issubclass(table, tables.OfficiallyNamed) or issubclass(table, tables.UnofficiallyNamed), table
assert hasattr(table, 'identifier'), table assert hasattr(table, 'identifier'), table
else: else:
assert not hasattr(table, 'identifier'), table assert not hasattr(table, 'identifier'), table
if not issubclass(table, tables.LanguageSpecific):
assert not hasattr(table, 'name'), table

View file

@ -16,16 +16,6 @@ class TestStrings(object):
tables.Pokemon.name == u"Marowak") tables.Pokemon.name == u"Marowak")
assert q.one().identifier == 'marowak' assert q.one().identifier == 'marowak'
def test_gt(self):
# Assuming that the identifiers are just lowercase names
q1 = self.connection.query(tables.Pokemon).filter(
tables.Pokemon.name > u"Xatu").order_by(
tables.Pokemon.id)
q2 = self.connection.query(tables.Pokemon).filter(
tables.Pokemon.identifier > u"xatu").order_by(
tables.Pokemon.id)
assert q1.all() == q2.all()
def test_languages(self): def test_languages(self):
q = self.connection.query(tables.Pokemon).filter( q = self.connection.query(tables.Pokemon).filter(
tables.Pokemon.name == u"Mightyena") tables.Pokemon.name == u"Mightyena")
@ -36,7 +26,9 @@ class TestStrings(object):
('roomaji', u'Guraena'), ('roomaji', u'Guraena'),
('fr', u'Grahyèna'), ('fr', u'Grahyèna'),
): ):
assert pkmn.names[lang] == name language = self.connection.query(tables.Language).filter_by(
identifier=lang).one()
assert pkmn.name_map[language] == name
@raises(KeyError) @raises(KeyError)
def test_bad_lang(self): def test_bad_lang(self):
@ -50,12 +42,10 @@ class TestStrings(object):
identifier=u"jade-orb").one() identifier=u"jade-orb").one()
language = self.connection.query(tables.Language).filter_by( language = self.connection.query(tables.Language).filter_by(
identifier=u"de").one() identifier=u"de").one()
item.names['de'] = u"foo" item.name_map[language] = u"foo"
assert item.names['de'] == "foo" assert item.name_map[language] == "foo"
assert item.names[language] == "foo" item.name_map[language] = u"xyzzy"
item.names[language] = u"xyzzy" assert item.name_map[language] == "xyzzy"
assert item.names['de'] == "xyzzy"
assert item.names[language] == "xyzzy"
def test_mutating_default(self): def test_mutating_default(self):
item = self.connection.query(tables.Item).filter_by( item = self.connection.query(tables.Item).filter_by(
@ -66,14 +56,12 @@ class TestStrings(object):
def test_string_mapping(self): def test_string_mapping(self):
item = self.connection.query(tables.Item).filter_by( item = self.connection.query(tables.Item).filter_by(
identifier=u"jade-orb").one() identifier=u"jade-orb").one()
assert len(item.names) == len(item.texts) assert len(item.name_map) == len(item.names)
for lang in item.texts: for lang in item.names:
assert item.names[lang] == item.texts[lang].name assert item.name_map[lang] == item.names[lang].name
assert item.names[lang] == item.names[lang.identifier] assert lang in item.name_map
assert lang in item.names assert "language that doesn't exist" not in item.name_map
assert lang.identifier in item.names assert tables.Language() not in item.name_map
assert "language that doesn't exist" not in item.names
assert tables.Language() not in item.names
def test_new_language(self): def test_new_language(self):
item = self.connection.query(tables.Item).filter_by( item = self.connection.query(tables.Item).filter_by(
@ -84,23 +72,16 @@ class TestStrings(object):
language.iso639 = language.iso3166 = u'--' language.iso639 = language.iso3166 = u'--'
language.official = False language.official = False
self.connection.add(language) self.connection.add(language)
item.names[u'test'] = u"foo" item.name_map[language] = u"foo"
assert item.names[language] == "foo" assert item.name_map[language] == "foo"
assert item.names['test'] == "foo" assert language in item.name_map
assert 'de' in item.names item.name_map[language] = u"xyzzy"
assert language in item.names assert item.name_map[language] == "xyzzy"
item.names[language] = u"xyzzy"
assert item.names[language] == "xyzzy"
assert item.names['test'] == "xyzzy"
@raises(NotImplementedError)
def test_delstring(self):
item = self.connection.query(tables.Item).filter_by(
identifier=u"jade-orb").one()
del item.names['en']
def test_markdown(self): def test_markdown(self):
move = self.connection.query(tables.Move).filter_by( move = self.connection.query(tables.Move).filter_by(
identifier=u"thunderbolt").one() identifier=u"thunderbolt").one()
language = self.connection.query(tables.Language).filter_by(
identifier=u"en").one()
assert '10%' in move.effect.as_text assert '10%' in move.effect.as_text
assert '10%' in move.effects['en'].as_text assert '10%' in move.effect_map[language].as_text