Pokemon species split: utilities.

Remove 'simple' altogether, as pokémon are now sane by default!
This commit is contained in:
Petr Viktorin 2011-04-30 02:42:42 +03:00
parent bc7e9128e8
commit dd0d225228
3 changed files with 21 additions and 144 deletions

View file

@ -12,8 +12,7 @@ from pokedex.db import tables
### Getter ### Getter
def get(session, table, identifier=None, name=None, id=None, def get(session, table, identifier=None, name=None, id=None, language=None):
form_identifier=None, form_name=None, language=None, is_pokemon=None):
"""Get one object from the database. """Get one object from the database.
session: The session to use (from pokedex.db.connect()) session: The session to use (from pokedex.db.connect())
@ -22,26 +21,16 @@ def get(session, table, identifier=None, name=None, id=None,
identifier: Identifier of the object identifier: Identifier of the object
name: The name of the object name: The name of the object
id: The ID number of the object id: The ID number of the object
form_identifier: For pokemon, identifier of the form
form_name: For pokemon, name of the form
language: A Language to use for name and form_name language: A Language to use for name and form_name
is_pokemon: If true, specifies that the table should be treated as a
pokemon table (handling forms specially). If None and table is the
(unaliased) Pokemon, it is set to True. Otherwise, the pokemon forms
aren't handled.
All conditions must match, so it's not a good idea to specify more than one All conditions must match, so it's not a good idea to specify more than one
of identifier/name/id at once. of identifier/name/id at once.
If zero or more than one objects matching the criteria are found, the If zero or more than one objects matching the criteria are found, the
appropriate SQLAlchemy exception is raised. appropriate SQLAlchemy exception is raised.
Exception: for pokemon, selects the form base unless form_* is given.
""" """
if is_pokemon is None:
is_pokemon = (table is tables.Pokemon)
query = session.query(table) query = session.query(table)
if identifier is not None: if identifier is not None:
@ -53,52 +42,34 @@ def get(session, table, identifier=None, name=None, id=None,
if id is not None: if id is not None:
query = query.filter_by(id=id) query = query.filter_by(id=id)
if form_identifier is not None or form_name is not None:
if is_pokemon:
query = query.join(table.unique_form)
if form_identifier is not None:
query = query.filter(tables.PokemonForm.identifier ==
form_identifier)
if form_name is not None:
query = filter_name(query, table, form_name, language)
else:
raise ValueError(
"form_identifier and form_name only make sense for pokemon")
elif is_pokemon:
query = filter_base_forms(query)
return query.one() return query.one()
### Helpers ### Helpers
def filter_name(query, table, name, language): def filter_name(query, table, name, language, name_attribute='name'):
"""Filter a query by name, return the resulting query """Filter a query by name, return the resulting query
query: The query to filter query: The query to filter
table: The table of named objects table: The table of named objects
name: The name to look for. May be a tuple of alternatives. name: The name to look for. May be a tuple of alternatives.
language: The language for "name", or None for the session default language: The language for "name", or None for the session default
name_attribute: the attribute to use; defaults to 'name'
""" """
if language is None: if language is None:
query = query.filter(table.name == name) query = query.filter(getattr(table, name_attribute) == name)
else: else:
names_table = table.names_table names_table = table.names_table
name_column = getattr(names_table, name_attribute)
query = query.join(names_table) query = query.join(names_table)
query = query.filter(names_table.foreign_id == table.id) query = query.filter(names_table.foreign_id == table.id)
query = query.filter(names_table.local_language_id == language.id) query = query.filter(names_table.local_language_id == language.id)
if isinstance(name, tuple): if isinstance(name, tuple):
query = query.filter(names_table.name in name) query = query.filter(name_column in name)
else: else:
query = query.filter(names_table.name == name) query = query.filter(name_column == name)
return query return query
def filter_base_forms(query): def order_by_name(query, table, language=None, *extra_languages, **kwargs):
"""Filter only base forms of pokemon, and return the resulting query
"""
query = query.filter(tables.Pokemon.forms.any())
return query
def order_by_name(query, table, language=None, *extra_languages):
"""Order a query by name. """Order a query by name.
query: The query to order query: The query to order
@ -108,12 +79,17 @@ def order_by_name(query, table, language=None, *extra_languages):
extra_languages: Extra languages to order by, should the translations for extra_languages: Extra languages to order by, should the translations for
`language` be incomplete (or ambiguous). `language` be incomplete (or ambiguous).
name_attribute (keyword argument): the attribute to use; defaults to 'name'
Uses the identifier as a fallback ordering. Uses the identifier as a fallback ordering.
""" """
name_attribute = kwargs.pop('name', 'name')
if kwargs:
raise ValueError('Unexpected keyword arguments: %s' % kwargs.keys())
order_columns = [] order_columns = []
if language is None: if language is None:
query = query.outerjoin(table.names_local) query = query.outerjoin(table.names_local)
order_columns.append(func.lower(table.names_table.name)) order_columns.append(func.lower(getattr(table.names_table, name_attribute)))
else: else:
extra_languages = (language, ) + extra_languages extra_languages = (language, ) + extra_languages
for language in extra_languages: for language in extra_languages:
@ -121,7 +97,7 @@ def order_by_name(query, table, language=None, *extra_languages):
query = query.outerjoin(names_table) query = query.outerjoin(names_table)
query = query.filter(names_table.foreign_id == table.id) query = query.filter(names_table.foreign_id == table.id)
query = query.filter(names_table.local_language_id == language.id) query = query.filter(names_table.local_language_id == language.id)
order_columns.append(func.lower(names_table.name)) order_columns.append(func.lower(getattr(names_table, name_attribute)))
order_columns.append(table.identifier) order_columns.append(table.identifier)
query = query.order_by(coalesce(*order_columns)) query = query.order_by(coalesce(*order_columns))
return query return query

View file

@ -3,7 +3,6 @@ from nose.tools import *
import unittest import unittest
from pokedex.db import connect, tables, util from pokedex.db import connect, tables, util
from pokedex.util import simple
session = connect() session = connect()
@ -19,32 +18,21 @@ def test_get_english_by_identifier():
language = util.get(session, tables.Language, 'en') language = util.get(session, tables.Language, 'en')
assert language.name == 'English' assert language.name == 'English'
def test_get_pokemon_baseform_identifier(): def test_get_pokemon_identifier():
for identifier in 'burmy shaymin unown cresselia'.split(): for identifier in 'burmy shaymin unown cresselia'.split():
poke = util.get(session, tables.Pokemon, identifier=identifier) poke = util.get(session, tables.PokemonSpecies, identifier=identifier)
assert poke.identifier == identifier assert poke.identifier == identifier
assert poke.is_base_form
def test_get_pokemon_baseform_name(): def test_get_pokemon_name():
for name in 'Burmy Shaymin Unown Cresselia'.split(): for name in 'Burmy Shaymin Unown Cresselia'.split():
poke = util.get(session, tables.Pokemon, name=name) poke = util.get(session, tables.PokemonSpecies, name=name)
assert poke.name == name assert poke.name == name
assert poke.is_base_form
def test_get_pokemon_baseform_name_explicit_language(): def test_get_pokemon_name_explicit_language():
french = util.get(session, tables.Language, 'fr') french = util.get(session, tables.Language, 'fr')
for name in 'Cheniti Shaymin Zarbi Cresselia'.split(): for name in 'Cheniti Shaymin Zarbi Cresselia'.split():
poke = util.get(session, tables.Pokemon, name=name, language=french) poke = util.get(session, tables.PokemonSpecies, name=name, language=french)
assert poke.name_map[french] == name, poke.name_map[french] assert poke.name_map[french] == name, poke.name_map[french]
assert poke.is_base_form
def test_get_pokemon_other_form_identifier():
for ii in 'wormadam/trash shaymin/sky shaymin/land'.split():
pokemon_identifier, form_identifier = ii.split('/')
poke = util.get(session, tables.Pokemon, identifier=pokemon_identifier, form_identifier=form_identifier)
assert poke.identifier == pokemon_identifier
if poke.form.unique_pokemon_id:
assert poke.form.identifier == form_identifier
def test_types_french_order(): def test_types_french_order():
french = util.get(session, tables.Language, 'fr') french = util.get(session, tables.Language, 'fr')
@ -52,24 +40,3 @@ def test_types_french_order():
types = list(util.order_by_name(types, tables.Type, language=french)) types = list(util.order_by_name(types, tables.Type, language=french))
assert types[0].name_map[french] == 'Acier', types[0].name_map[french] assert types[0].name_map[french] == 'Acier', types[0].name_map[french]
assert types[-1].name_map[french] == 'Vol', types[-1].name_map[french] assert types[-1].name_map[french] == 'Vol', types[-1].name_map[french]
def test_simple_pokemon():
pokemon = simple.pokemon(session)
assert pokemon[0].identifier == 'bulbasaur'
assert pokemon[-1].identifier == 'genesect'
def test_simple_types():
types = simple.types(session)
assert types[0].identifier == 'bug'
assert types[-1].identifier == 'water'
def test_simple_moves():
moves = simple.moves(session)
assert moves[0].identifier == 'absorb'
assert moves[-1].identifier == 'zen-headbutt'
def test_simple_items():
items = simple.items(session)
assert items[0].identifier == 'ability-urge'
assert items[-1].identifier == 'zoom-lens'

View file

@ -1,66 +0,0 @@
"""Simple lists of things for simple scripts
If you want to get a pokemon list, and you don't want it to include three
Wormadams and a whole bunch of Rotoms because of how the database is
structured, this module is for you.
The returned queries basically contain what a pokedex would show you.
You should make no other assumptions about them.
If you need to make assumptions, feel free to use these functions as examples
of what to watch out for.
"""
from pokedex.db import tables
from pokedex.db.util import filter_base_forms, order_by_name
def pokemon(session):
"""Get a "sane" list of pokemon
WARNING: The result of this function is not very well defined.
If you want something specific, build that specific query yourself.
Currently, all base forms are returned, in evolution-preserving order
"""
query = session.query(tables.Pokemon)
query = query.order_by(tables.Pokemon.order)
query = filter_base_forms(query)
return query
def moves(session):
"""Get a "sane" list of moves
WARNING: The result of this function is not very well defined.
If you want something specific, build that specific query yourself.
Currently, moves from mainline games are returned, sored by name
"""
query = session.query(tables.Move)
query = order_by_name(query, tables.Move)
query = query.filter(tables.Move.id < 10000)
return query
def types(session):
"""Get a "sane" list of types
WARNING: The result of this function is not very well defined.
If you want something specific, build that specific query yourself.
Currently, generation V types are returned, sored by name
"""
query = session.query(tables.Type)
query = order_by_name(query, tables.Type)
query = query.filter(tables.Type.id < 10000)
return query
def items(session):
"""Get a "sane" list of items
WARNING: The result of this function is not very well defined.
If you want something specific, build that specific query yourself.
Currently, items are sored by name
"""
query = session.query(tables.Item)
query = order_by_name(query, tables.Item)
return query