diff --git a/pokedex/compatibility.py b/pokedex/compatibility.py index 4eea75b..49c151d 100644 --- a/pokedex/compatibility.py +++ b/pokedex/compatibility.py @@ -3,6 +3,7 @@ Currently these are functions missing from Python 2.5. """ from __future__ import print_function +import six try: from itertools import permutations @@ -67,7 +68,7 @@ except ImportError: # Parse and validate the field names. Validation serves two purposes, # generating informative error messages and preventing template injection attacks. - if isinstance(field_names, basestring): + if isinstance(field_names, six.string_types): field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas field_names = tuple(map(str, field_names)) if rename: diff --git a/pokedex/db/__init__.py b/pokedex/db/__init__.py index 3e8ecb1..07de822 100644 --- a/pokedex/db/__init__.py +++ b/pokedex/db/__init__.py @@ -4,7 +4,7 @@ import re from sqlalchemy import engine_from_config, orm from ..defaults import get_default_db_uri -from .tables import Language, metadata +from .tables import metadata from .multilang import MultilangSession, MultilangScopedSession ENGLISH_ID = 9 @@ -46,7 +46,7 @@ def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''): ### Connect engine_args[engine_prefix + 'url'] = uri engine = engine_from_config(engine_args, prefix=engine_prefix) - conn = engine.connect() + engine.connect() metadata.bind = engine all_session_args = dict(autoflush=True, autocommit=False, bind=engine) diff --git a/pokedex/db/load.py b/pokedex/db/load.py index 7a195a0..2ecc109 100644 --- a/pokedex/db/load.py +++ b/pokedex/db/load.py @@ -3,7 +3,6 @@ from __future__ import print_function import csv import fnmatch -import io import os.path import sys @@ -12,7 +11,7 @@ import sqlalchemy.sql.util import sqlalchemy.types import pokedex -from pokedex.db import metadata, tables, translations +from pokedex.db import metadata, translations from pokedex.defaults import get_default_csv_dir from pokedex.db.dependencies import find_dependent_tables from pokedex.db.oracle import rewrite_long_table_names @@ -323,7 +322,7 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s # Could happen if row A refers to B which refers to C. # This is ridiculous and doesn't happen in my data so far raise ValueError("Too many levels of self-reference! " - "Row was: " + str(row)) + "Row was: " + str(row_data)) session.execute( insert_stmt.values(**row_data) diff --git a/pokedex/db/markdown.py b/pokedex/db/markdown.py index 8bbc0d0..115faa4 100644 --- a/pokedex/db/markdown.py +++ b/pokedex/db/markdown.py @@ -174,7 +174,7 @@ class PokedexLinkPattern(markdown.inlinepatterns.Pattern): self.game_language = game_language def handleMatch(self, m): - from pokedex.db import tables, util + from pokedex.db import tables start, label, category, target, end = m.groups() try: table = dict( diff --git a/pokedex/db/multilang.py b/pokedex/db/multilang.py index 06a5ab8..00cdb33 100644 --- a/pokedex/db/multilang.py +++ b/pokedex/db/multilang.py @@ -1,7 +1,5 @@ -from functools import partial - from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy -from sqlalchemy.orm import Query, aliased, mapper, relationship, synonym +from sqlalchemy.orm import Query, mapper, relationship, synonym from sqlalchemy.orm.collections import attribute_mapped_collection from sqlalchemy.orm.scoping import ScopedSession from sqlalchemy.orm.session import Session, object_session diff --git a/pokedex/db/tables.py b/pokedex/db/tables.py index 322d756..b5e20ba 100644 --- a/pokedex/db/tables.py +++ b/pokedex/db/tables.py @@ -26,18 +26,15 @@ classes in that module can be used to change the default language. """ # XXX: Check if "gametext" is set correctly everywhere -import collections from functools import partial +import six -from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint +from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, UniqueConstraint from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import backref, relationship -from sqlalchemy.orm.session import Session -from sqlalchemy.orm.interfaces import AttributeExtension -from sqlalchemy.sql import and_, or_ -from sqlalchemy.schema import ColumnDefault +from sqlalchemy.sql import and_ from sqlalchemy.types import Boolean, Enum, Integer, SmallInteger, Unicode, UnicodeText from pokedex.db import markdown, multilang @@ -56,7 +53,7 @@ class TableSuperclass(object): if not pk_constraint: return u"<%s object at %x>" % (typename, id(self)) - pk = u', '.join(unicode(getattr(self, column.name)) + pk = u', '.join(six.text_type(getattr(self, column.name)) for column in pk_constraint.columns) try: return u"<%s object (%s): %s>" % (typename, pk, self.identifier) @@ -64,10 +61,13 @@ class TableSuperclass(object): return u"<%s object (%s)>" % (typename, pk) def __str__(self): - return unicode(self).encode('utf8') + if six.PY2: + return six.text_type(self).encode('utf8') + else: + return type(self).__unicode__(self) def __repr__(self): - return unicode(self).encode('utf8') + return str(self) mapped_classes = [] class TableMetaclass(DeclarativeMeta): diff --git a/pokedex/db/translations.py b/pokedex/db/translations.py index 05a04fa..606a66d 100755 --- a/pokedex/db/translations.py +++ b/pokedex/db/translations.py @@ -30,6 +30,7 @@ import os import re from collections import defaultdict +import six from six.moves import zip from pokedex.db import tables @@ -155,10 +156,13 @@ class Message(object): return template.format(self=self, string=string) def __str__(self): - return unicode(self).encode('utf-8') + if six.PY2: + return six.text_type(self).encode('utf8') + else: + return type(self).__unicode__(self) def __repr__(self): - return unicode(self).encode('utf-8') + return str(self) class Translations(object): """Data and opertaions specific to a location on disk (and a source language) @@ -648,7 +652,6 @@ def match_to_source(source, *translations): if first or match: best_string = current_string best_crc = current_crc - best_message = translation if match: break first = False diff --git a/pokedex/db/util.py b/pokedex/db/util.py index 6c26d67..8f461c1 100644 --- a/pokedex/db/util.py +++ b/pokedex/db/util.py @@ -9,8 +9,6 @@ from sqlalchemy.sql.expression import func from sqlalchemy.sql.functions import coalesce from sqlalchemy.orm.exc import NoResultFound -from pokedex.db import tables - ### Getter def get(session, table, identifier=None, name=None, id=None, language=None): diff --git a/pokedex/doc/tabledoc.py b/pokedex/doc/tabledoc.py index 04bdfda..0acef52 100644 --- a/pokedex/doc/tabledoc.py +++ b/pokedex/doc/tabledoc.py @@ -9,19 +9,17 @@ but documents Pokédex mapped classes. import functools import textwrap +import six from docutils import nodes from docutils.statemachine import ViewList -from sphinx.util.compat import Directive, make_admonition -from sphinx.locale import _ from sphinx.domains.python import PyClasslike -from sphinx.util.docfields import Field, GroupedField, TypedField -from sphinx.ext.autodoc import ClassLevelDocumenter +from sphinx.util.docfields import TypedField from sqlalchemy import types from sqlalchemy.orm.attributes import InstrumentedAttribute from sqlalchemy.orm.properties import RelationshipProperty -from sqlalchemy.orm import Mapper, configure_mappers +from sqlalchemy.orm import configure_mappers from sqlalchemy.ext.associationproxy import AssociationProxy from pokedex.db.markdown import MoveEffectPropertyMap, MoveEffectProperty @@ -128,7 +126,7 @@ def with_header(header=None): ### Section generation functions def generate_table_header(cls, remaining_attrs): - first_line, sep, next_lines = unicode(cls.__doc__).partition(u'\n') + first_line, sep, next_lines = six.text_type(cls.__doc__).partition(u'\n') yield first_line for line in textwrap.dedent(next_lines).split('\n'): yield line @@ -184,7 +182,7 @@ def generate_columns(cls, remaining_attrs): yield column_header(c, name) + ':' yield u'' if c.doc: - yield u' ' + unicode(c.doc) + yield u' ' + six.text_type(c.doc) yield u'' @with_header(u'Internationalized strings') @@ -200,7 +198,7 @@ def generate_strings(cls, remaining_attrs): translation_class.__table__.name) yield u'' if c.doc: - yield u' ' + unicode(c.doc) + yield u' ' + six.text_type(c.doc) yield u'' @with_header(u'Relationships') @@ -220,7 +218,7 @@ def generate_relationships(cls, remaining_attrs): yield u'(→ %s)' % class_name if rel.doc: yield u'' - yield u' ' + unicode(rel.doc) + yield u' ' + six.text_type(rel.doc) if rel.secondary is not None: yield u'' yield ' Association table: ``%s``' % rel.secondary @@ -299,7 +297,6 @@ class DexTable(PyClasslike): break else: raise ValueError('Table %s not found' % name) - table = cls.__table__ remaining_attrs = set(x for x in dir(cls) if not x.startswith('_')) remaining_attrs.difference_update(['metadata', 'translation_classes', diff --git a/pokedex/formulae.py b/pokedex/formulae.py index 62271f1..d942d74 100644 --- a/pokedex/formulae.py +++ b/pokedex/formulae.py @@ -2,7 +2,7 @@ """Faithful translations of calculations the games make.""" from __future__ import division -from itertools import izip +from six.moves import reduce, xrange, zip def nCr(n, r): """n-choose-r. @@ -13,7 +13,7 @@ def nCr(n, r): return reduce( lambda x, y: x * y[0] / y[1], - izip(xrange(n - r + 1, n + 1), + zip(xrange(n - r + 1, n + 1), xrange(1, r + 1)), 1) diff --git a/pokedex/struct/_pokemon_struct.py b/pokedex/struct/_pokemon_struct.py index ba67eff..80a987b 100644 --- a/pokedex/struct/_pokemon_struct.py +++ b/pokedex/struct/_pokemon_struct.py @@ -6,7 +6,9 @@ format sent back and forth over the GTS. import datetime -from construct import * +from construct import (Adapter, BitField, BitStruct, Buffered, + EmbeddedBitStruct, Enum, Flag, Padding, String, Struct, + ULInt16, ULInt32, ULInt8) # TODO: # - strings should be validated, going both in and out diff --git a/pokedex/tests/test_database_sanity.py b/pokedex/tests/test_database_sanity.py index 276491b..f5747ca 100644 --- a/pokedex/tests/test_database_sanity.py +++ b/pokedex/tests/test_database_sanity.py @@ -5,7 +5,7 @@ from sqlalchemy.orm import aliased, joinedload, lazyload from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.sql import func -from pokedex.db import connect, tables, util +from pokedex.db import tables, util def test_encounter_slots(session): """Encounters have a version, which has a version group; encounters also diff --git a/pokedex/tests/test_schema.py b/pokedex/tests/test_schema.py index 736e960..0a17dc4 100644 --- a/pokedex/tests/test_schema.py +++ b/pokedex/tests/test_schema.py @@ -3,11 +3,10 @@ import pytest from sqlalchemy import Column, Integer, String, create_engine -from sqlalchemy.orm import class_mapper, joinedload, sessionmaker -from sqlalchemy.orm.session import Session +from sqlalchemy.orm import joinedload, sessionmaker from sqlalchemy.ext.declarative import declarative_base -from pokedex.db import tables, markdown +from pokedex.db import tables from pokedex.db.multilang import MultilangScopedSession, MultilangSession, \ create_translation_table diff --git a/pokedex/tests/test_strings.py b/pokedex/tests/test_strings.py index 0517460..1c7978f 100644 --- a/pokedex/tests/test_strings.py +++ b/pokedex/tests/test_strings.py @@ -3,8 +3,6 @@ import pytest parametrize = pytest.mark.parametrize -from sqlalchemy.orm.exc import NoResultFound - from pokedex.db import tables, connect, util, markdown @pytest.fixture(scope="module") diff --git a/pokedex/tests/test_util.py b/pokedex/tests/test_util.py index 4f2a6d1..96000e5 100644 --- a/pokedex/tests/test_util.py +++ b/pokedex/tests/test_util.py @@ -3,7 +3,7 @@ import pytest parametrize = pytest.mark.parametrize -from pokedex.db import connect, tables, util +from pokedex.db import tables, util def test_get_item_identifier(session): item = util.get(session, tables.Item, identifier='master-ball') diff --git a/pokedex/util/media.py b/pokedex/util/media.py index 0b4f60d..cb1abaa 100644 --- a/pokedex/util/media.py +++ b/pokedex/util/media.py @@ -32,6 +32,7 @@ All images are in the PNG format, except animations (GIF). All sounds are OGGs. import os from functools import partial +import six class MediaFile(object): """Represents a file: picture, sound, etc. @@ -83,7 +84,7 @@ class MediaFile(object): class BaseMedia(object): def __init__(self, root): - if isinstance(root, basestring): + if isinstance(root, six.string_types): self.file_class = partial(MediaFile, root) else: self.file_class = root @@ -179,7 +180,7 @@ class _BasePokemonMedia(BaseMedia): If the sprite is not found, raise a ValueError. """ - if isinstance(version, basestring): + if isinstance(version, six.string_types): version_dir = version try: generation, info = self._pokemon_sprite_info[version_dir]