diff --git a/.gitignore b/.gitignore index 84ec61b..49c834a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.egg-info *.pyc +*.bak .*.sw? build docs/build diff --git a/baph/__init__.py b/baph/__init__.py index 921098f..c931996 100644 --- a/baph/__init__.py +++ b/baph/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import def setup(): from baph.apps import apps from baph.conf import settings diff --git a/baph/apps/config.py b/baph/apps/config.py index 75a145f..f0935af 100644 --- a/baph/apps/config.py +++ b/baph/apps/config.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os from importlib import import_module diff --git a/baph/apps/registry.py b/baph/apps/registry.py index 1fd9f62..4fe9d3f 100644 --- a/baph/apps/registry.py +++ b/baph/apps/registry.py @@ -1,7 +1,13 @@ +from __future__ import absolute_import import threading from collections import Counter, OrderedDict, defaultdict -from functools32 import lru_cache +from six import PY2 + +if PY2: + from functools32 import lru_cache +else: + from functools import lru_cache from .config import AppConfig @@ -80,7 +86,7 @@ def get_app_configs(self): Imports applications and returns an iterable of app configs. """ self.check_apps_ready() - return self.app_configs.values() + return list(self.app_configs.values()) @lru_cache(maxsize=None) def get_models(self, include_auto_created=False, diff --git a/baph/auth/__init__.py b/baph/auth/__init__.py index 279642e..b767914 100644 --- a/baph/auth/__init__.py +++ b/baph/auth/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from datetime import datetime from django.conf import settings diff --git a/baph/auth/apps.py b/baph/auth/apps.py index 32000f4..79143c5 100644 --- a/baph/auth/apps.py +++ b/baph/auth/apps.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from baph.apps import AppConfig diff --git a/baph/auth/backends.py b/baph/auth/backends.py index b74f618..78a7e50 100644 --- a/baph/auth/backends.py +++ b/baph/auth/backends.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import django.core.validators from baph.auth.models import User, Organization diff --git a/baph/auth/decorators.py b/baph/auth/decorators.py index f00a68d..e52134a 100644 --- a/baph/auth/decorators.py +++ b/baph/auth/decorators.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import import decorator import logging import time @@ -6,6 +7,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth.decorators import user_passes_test from django.http import HttpResponseRedirect +from six.moves import zip def check_perm(resource, action, simple=True, extra_keys={}, filters={}): @@ -23,8 +25,8 @@ def check_perm(resource, action, simple=True, extra_keys={}, filters={}): def check_perm_closure(f, request, *args, **kwargs): if not kwargs: - keys = f.func_code.co_varnames[1:] #item 0 is 'request' - kwargs = dict(zip(keys,args)) + keys = f.__code__.co_varnames[1:] #item 0 is 'request' + kwargs = dict(list(zip(keys,args))) args = [] for url_key, db_key in extra_keys.items(): @@ -68,6 +70,6 @@ def wrapper(*arg): t1 = time.time() res = func(*arg) t2 = time.time() - logging.debug('%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)) + logging.debug('%s took %0.3f ms' % (func.__name__, (t2-t1)*1000.0)) return res return wrapper diff --git a/baph/auth/forms.py b/baph/auth/forms.py index 90e3135..8dd17a0 100644 --- a/baph/auth/forms.py +++ b/baph/auth/forms.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- #from baph.sites.models import get_current_site +from __future__ import absolute_import from coffin.shortcuts import render_to_string from django import forms from django.contrib.auth.forms import SetPasswordForm as BaseSetPasswordForm diff --git a/baph/auth/management/__init__.py b/baph/auth/management/__init__.py index fc528a5..a96cf37 100644 --- a/baph/auth/management/__init__.py +++ b/baph/auth/management/__init__.py @@ -1,4 +1,6 @@ from __future__ import unicode_literals +from __future__ import absolute_import +from __future__ import print_function import getpass import locale import unicodedata @@ -84,14 +86,17 @@ def _get_all_permissions(opts): def create_permissions(app, created_models, verbosity, db=DEFAULT_DB_ALIAS, **kwargs): + pkg, _ = app.__name__.rsplit('.', 1) app_models = [] for k, v in vars(app).items(): if k not in orm.Base._decl_class_registry: continue - if v not in orm.Base._decl_class_registry.values(): + if v not in list(orm.Base._decl_class_registry.values()): continue - if hasattr(app, '__package__') and app.__package__ + '.models' != v.__module__: + if pkg + '.models' != v.__module__: continue + #if hasattr(app, '__package__') and app.__package__ + '.models' != v.__module__: + # continue app_models.append( (k,v) ) if not app_models: return @@ -143,8 +148,8 @@ def create_permissions(app, created_models, verbosity, db=DEFAULT_DB_ALIAS, if verbosity >= 2: for perm in perms: - print("Adding permission '%s:%s'" % (perm['resource'], - perm['codename'])) + print(("Adding permission '%s:%s'" % (perm['resource'], + perm['codename']))) ''' def create_superuser(app, created_models, verbosity, db, **kwargs): diff --git a/baph/auth/management/commands/createpermissions.py b/baph/auth/management/commands/createpermissions.py index 542d31f..8585fd2 100644 --- a/baph/auth/management/commands/createpermissions.py +++ b/baph/auth/management/commands/createpermissions.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import sys import os from optparse import make_option diff --git a/baph/auth/middleware.py b/baph/auth/middleware.py index e9e0be3..c00e81f 100644 --- a/baph/auth/middleware.py +++ b/baph/auth/middleware.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.utils.functional import SimpleLazyObject from . import get_user as _get_user diff --git a/baph/auth/mixins.py b/baph/auth/mixins.py index 94e6406..22c42d5 100644 --- a/baph/auth/mixins.py +++ b/baph/auth/mixins.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import json import logging @@ -10,13 +11,15 @@ from baph.db import ORM from baph.db.models.loading import cache from baph.db.models.utils import class_resolver, column_to_attr, key_to_value +import six +from six.moves import zip logger = logging.getLogger('authorization') def convert_filter(k, cls=None): """Convert a string filter into a column-based filter""" - if not isinstance(k, basestring): + if not isinstance(k, six.string_types): raise Exception('convert_filters keys must be strings') frags = k.split('.') attr = frags.pop() @@ -402,7 +405,7 @@ def get_resource_filters(self, resource, action='view'): # exact filter values = p.value.split(',') - data = zip(keys, values) + data = list(zip(keys, values)) filters = [] for key, value in data: diff --git a/baph/auth/models/__init__.py b/baph/auth/models/__init__.py index 5cc65e2..fe14394 100644 --- a/baph/auth/models/__init__.py +++ b/baph/auth/models/__init__.py @@ -1,11 +1,12 @@ +from __future__ import print_function from .permission import Permission -print 'Permission imported' +print('Permission imported') from .organization import Organization -print 'Organization imported' +print('Organization imported') from .group import Group -print 'Group imported' +print('Group imported') from .user import AnonymousUser, User -print 'User imported' +print('User imported') from .usergroup import UserGroup from .permissionassociation import PermissionAssociation from .oauth_ import OAuthConsumer, OAuthNonce diff --git a/baph/auth/models/group/__init__.py b/baph/auth/models/group/__init__.py index 4ce496a..7b62d01 100644 --- a/baph/auth/models/group/__init__.py +++ b/baph/auth/models/group/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.orm import RelationshipProperty diff --git a/baph/auth/models/group/base.py b/baph/auth/models/group/base.py index ac3e9c8..8d9923a 100644 --- a/baph/auth/models/group/base.py +++ b/baph/auth/models/group/base.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from sqlalchemy import Column, Integer, Unicode from sqlalchemy.ext.associationproxy import association_proxy diff --git a/baph/auth/models/oauth_/__init__.py b/baph/auth/models/oauth_/__init__.py index b5c2fec..8f26146 100644 --- a/baph/auth/models/oauth_/__init__.py +++ b/baph/auth/models/oauth_/__init__.py @@ -1,5 +1,6 @@ +from __future__ import absolute_import from django.conf import settings -from oauth import oauth +import oauth2 as oauth from sqlalchemy import (Column, DateTime, ForeignKey, Integer, String, UniqueConstraint) from sqlalchemy.orm import relationship @@ -30,7 +31,7 @@ def as_consumer(self): '''Creates an oauth.OAuthConsumer object from the DB data. :rtype: oauth.OAuthConsumer ''' - return oauth.OAuthConsumer(self.key, self.secret) + return oauth.Consumer(self.key, self.secret) class OAuthNonce(Base): diff --git a/baph/auth/models/organization/base.py b/baph/auth/models/organization/base.py index c0bbbf7..d0fc04a 100644 --- a/baph/auth/models/organization/base.py +++ b/baph/auth/models/organization/base.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from sqlalchemy import Column, Integer, Unicode from baph.db import ORM diff --git a/baph/auth/models/permission/__init__.py b/baph/auth/models/permission/__init__.py index 28f1da9..fdddb7f 100644 --- a/baph/auth/models/permission/__init__.py +++ b/baph/auth/models/permission/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from sqlalchemy import Column, Integer, String, Unicode diff --git a/baph/auth/models/permission/utils.py b/baph/auth/models/permission/utils.py index 39f4b2b..674e493 100644 --- a/baph/auth/models/permission/utils.py +++ b/baph/auth/models/permission/utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import funcy as f from baph.auth.models.permission import Permission diff --git a/baph/auth/models/permissionassociation/__init__.py b/baph/auth/models/permissionassociation/__init__.py index 4388b67..088db6e 100644 --- a/baph/auth/models/permissionassociation/__init__.py +++ b/baph/auth/models/permissionassociation/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.ext.associationproxy import association_proxy diff --git a/baph/auth/models/user/__init__.py b/baph/auth/models/user/__init__.py index 5173247..8e405da 100644 --- a/baph/auth/models/user/__init__.py +++ b/baph/auth/models/user/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from datetime import datetime from django.contrib.auth.signals import user_logged_in diff --git a/baph/auth/models/user/base.py b/baph/auth/models/user/base.py index fa0464c..e88281c 100644 --- a/baph/auth/models/user/base.py +++ b/baph/auth/models/user/base.py @@ -1,5 +1,6 @@ +from __future__ import absolute_import from datetime import datetime -import urllib +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error from django.conf import settings from django.contrib.auth.hashers import check_password, make_password @@ -154,7 +155,7 @@ def get_absolute_url(self): :rtype: :class:`str` ''' - return '/users/%s/' % urllib.quote(smart_str(self.username)) + return '/users/%s/' % six.moves.urllib.parse.quote(smart_str(self.username)) def get_full_name(self): '''Retrieves the first_name plus the last_name, with a space in diff --git a/baph/auth/models/user/utils.py b/baph/auth/models/user/utils.py index 01d6425..5381bc3 100644 --- a/baph/auth/models/user/utils.py +++ b/baph/auth/models/user/utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import uuid from django.conf import settings diff --git a/baph/auth/models/usergroup/__init__.py b/baph/auth/models/usergroup/__init__.py index b19e468..f0c8376 100644 --- a/baph/auth/models/usergroup/__init__.py +++ b/baph/auth/models/usergroup/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from sqlalchemy import (Boolean, Column, ForeignKey, Index, Integer, PrimaryKeyConstraint, String) from sqlalchemy.orm import backref, relationship diff --git a/baph/auth/registration/decorators.py b/baph/auth/registration/decorators.py index 6083886..293fbde 100644 --- a/baph/auth/registration/decorators.py +++ b/baph/auth/registration/decorators.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from django.http import HttpResponsePermanentRedirect from django.utils.decorators import available_attrs diff --git a/baph/auth/registration/forms.py b/baph/auth/registration/forms.py index 12beeba..5773ff8 100644 --- a/baph/auth/registration/forms.py +++ b/baph/auth/registration/forms.py @@ -5,6 +5,7 @@ Forms and validation code for user registration. ''' +from __future__ import absolute_import from hashlib import sha1 as sha_constructor import random @@ -18,6 +19,7 @@ from baph.auth.registration.managers import SignupManager from baph.auth.utils import generate_sha1 from baph.db.orm import ORM +import six orm = ORM.get() @@ -188,7 +190,7 @@ def save(self): """ Generate a random username before falling back to parent signup form """ session = orm.sessionmaker() while True: - username = unicode(sha_constructor(str(random.random())).hexdigest()[:5]) + username = six.text_type(sha_constructor(six.ensure_binary(str(random.random()))).hexdigest()[:5]) user = session.query(User).filter(User.username==username).first() if not user: break @@ -211,7 +213,7 @@ def __init__(self, user, *args, **kwargs): """ super(ChangeEmailForm, self).__init__(*args, **kwargs) if not isinstance(user, User): - raise TypeError, "user must be an instance of %s" % User._meta.model_name + raise TypeError("user must be an instance of %s" % User._meta.model_name) else: self.user = user def clean_email(self): diff --git a/baph/auth/registration/managers.py b/baph/auth/registration/managers.py index 45c1335..efa56da 100644 --- a/baph/auth/registration/managers.py +++ b/baph/auth/registration/managers.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from datetime import datetime import re @@ -8,6 +9,7 @@ from baph.auth.registration.models import UserRegistration from baph.auth.utils import generate_sha1 from baph.db.orm import ORM +import six orm = ORM.get() @@ -19,7 +21,7 @@ class SignupManager(object): @staticmethod def create_user(username, email, password, active=False, send_email=True, **kwargs): - uname = username.encode('utf-8') if isinstance(username, unicode) else username + uname = username.encode('utf-8') if isinstance(username, six.text_type) else username salt, activation_key = generate_sha1(uname) #org_key = Organization._meta.verbose_name diff --git a/baph/auth/registration/models.py b/baph/auth/registration/models.py index 4a25443..ac9035b 100644 --- a/baph/auth/registration/models.py +++ b/baph/auth/registration/models.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import datetime from coffin.shortcuts import render_to_string diff --git a/baph/auth/registration/settings.py b/baph/auth/registration/settings.py index cf6bc35..39736e2 100644 --- a/baph/auth/registration/settings.py +++ b/baph/auth/registration/settings.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings diff --git a/baph/auth/registration/signals.py b/baph/auth/registration/signals.py index 81e0af7..25a4093 100644 --- a/baph/auth/registration/signals.py +++ b/baph/auth/registration/signals.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from django.dispatch import Signal # A new user has registered. diff --git a/baph/auth/registration/tests/backends.py b/baph/auth/registration/tests/backends.py index 0c3adb1..0ec56bc 100644 --- a/baph/auth/registration/tests/backends.py +++ b/baph/auth/registration/tests/backends.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest2 as unittest from django.conf import settings diff --git a/baph/auth/registration/tests/decorators.py b/baph/auth/registration/tests/decorators.py index 61a5c43..20f8fe8 100644 --- a/baph/auth/registration/tests/decorators.py +++ b/baph/auth/registration/tests/decorators.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import re from django.conf import settings @@ -27,7 +28,7 @@ def test_secure_required(self): # Test if the redirected url contains 'https'. Couldn't use # ``assertRedirects`` here because the redirected to page is # non-existant. - self.assertTrue('https' in str(response)) + self.assertTrue('https' in response._headers['location'][1]) # Set back to the old settings auth_settings.BAPH_USE_HTTPS = False diff --git a/baph/auth/registration/tests/forms.py b/baph/auth/registration/tests/forms.py index 6cb8032..d6c29d0 100644 --- a/baph/auth/registration/tests/forms.py +++ b/baph/auth/registration/tests/forms.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from baph.auth.models import User diff --git a/baph/auth/registration/tests/managers.py b/baph/auth/registration/tests/managers.py index 017541e..1c0b5ad 100644 --- a/baph/auth/registration/tests/managers.py +++ b/baph/auth/registration/tests/managers.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from __future__ import absolute_import import datetime import re diff --git a/baph/auth/registration/tests/models.py b/baph/auth/registration/tests/models.py index 2e0224b..8756cf5 100644 --- a/baph/auth/registration/tests/models.py +++ b/baph/auth/registration/tests/models.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from __future__ import absolute_import import datetime import hashlib import re diff --git a/baph/auth/registration/tests/views.py b/baph/auth/registration/tests/views.py index b559d93..f1baed0 100644 --- a/baph/auth/registration/tests/views.py +++ b/baph/auth/registration/tests/views.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from __future__ import absolute_import from datetime import datetime, timedelta from django.core.urlresolvers import reverse @@ -182,7 +183,7 @@ def test_signup_view_signout(self): 'tos': 'on'}) # And should now be signed out - self.failIf(len(self.client.session.keys()) > 0) + self.failIf(len(list(self.client.session.keys())) > 0) def test_signup_view_success(self): """ diff --git a/baph/auth/registration/urls.py b/baph/auth/registration/urls.py index 339b6e0..1a2f7b6 100644 --- a/baph/auth/registration/urls.py +++ b/baph/auth/registration/urls.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import try: from coffin.conf.urls.defaults import * except: diff --git a/baph/auth/registration/utils.py b/baph/auth/registration/utils.py index 03219ee..a67b1b6 100644 --- a/baph/auth/registration/utils.py +++ b/baph/auth/registration/utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from baph.auth.registration import settings diff --git a/baph/auth/registration/views.py b/baph/auth/registration/views.py index 3cf616e..786414b 100644 --- a/baph/auth/registration/views.py +++ b/baph/auth/registration/views.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- '''Views which allow users to create and activate accounts.''' +from __future__ import absolute_import from coffin.shortcuts import render_to_response, redirect from coffin.template import RequestContext from django.conf import settings as django_settings diff --git a/baph/auth/urls.py b/baph/auth/urls.py index 91f8744..f862940 100644 --- a/baph/auth/urls.py +++ b/baph/auth/urls.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from coffin.conf.urls.defaults import patterns urlpatterns = patterns('baph.auth.views', diff --git a/baph/auth/utils.py b/baph/auth/utils.py index ca344e5..e83832c 100644 --- a/baph/auth/utils.py +++ b/baph/auth/utils.py @@ -1,6 +1,9 @@ +from __future__ import absolute_import from hashlib import sha1 import random +from six import ensure_binary + # port from userena def generate_sha1(string, salt=None): @@ -19,7 +22,7 @@ def generate_sha1(string, salt=None): """ if not salt: - salt = sha1(str(random.random())).hexdigest()[:5] - hash = sha1(salt+str(string)).hexdigest() + salt = sha1(ensure_binary(str(random.random()))).hexdigest()[:5] + hash = sha1(ensure_binary(salt)+ensure_binary(string)).hexdigest() return (salt, hash) diff --git a/baph/auth/views.py b/baph/auth/views.py index 668b47d..2752058 100644 --- a/baph/auth/views.py +++ b/baph/auth/views.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import import inspect import re from uuid import UUID diff --git a/baph/conf/__init__.py b/baph/conf/__init__.py index fb931a0..fc7ed1e 100644 --- a/baph/conf/__init__.py +++ b/baph/conf/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import ast from contextlib import contextmanager import imp @@ -13,6 +14,7 @@ from django.utils.functional import LazyObject, empty from baph.core.preconfig.loader import PreconfigLoader +import six ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" @@ -47,9 +49,7 @@ def __new__(cls, name, bases, attrs): attrs['__module__'] = 'django.conf' return super(SettingsMeta, cls).__new__(cls, name, bases, attrs) -class LazySettings(LazyObject): - __metaclass__ = SettingsMeta - +class LazySettings(six.with_metaclass(SettingsMeta, LazyObject)): def _setup(self, name=None): settings_module = os.environ.get(ENVIRONMENT_VARIABLE) if not settings_module: @@ -201,7 +201,9 @@ def get_package_path(self, package): return None if not loader.is_package(package): raise ValueError('%r is not a package' % package) - self.package_paths[package] = loader.filename + fullpath = loader.get_filename() + path, filename = fullpath.rsplit('/', 1) + self.package_paths[package] = path return self.package_paths[package] @staticmethod @@ -222,7 +224,7 @@ def compile_module(module): content = fp.read() node = ast.parse(content, path) code = compile(node, path, 'exec') - exec code in module.__dict__ + exec(code, module.__dict__) def load_module_settings(self, module_name): msg = ' %s' % module_name diff --git a/baph/conf/preconfigure.py b/baph/conf/preconfigure.py index 6b31ef1..4926050 100644 --- a/baph/conf/preconfigure.py +++ b/baph/conf/preconfigure.py @@ -1,9 +1,12 @@ +from __future__ import absolute_import import argparse import imp import inspect import itertools import os import sys +import six +from six.moves import range PRECONFIG_MODULE_NAME = 'preconfig' @@ -136,7 +139,7 @@ def set_environment_var(self, key, value): " os.environ values must be strings " if value is None: value = '' - elif not isinstance(value, basestring): + elif not isinstance(value, six.string_types): value = str(value) os.environ[key] = value diff --git a/baph/contrib/oauth/store.py b/baph/contrib/oauth/store.py index 276e15e..31ec1ef 100644 --- a/baph/contrib/oauth/store.py +++ b/baph/contrib/oauth/store.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from datetime import datetime from django.conf import settings diff --git a/baph/contrib/sessions/models.py b/baph/contrib/sessions/models.py index 7378248..6753d19 100644 --- a/baph/contrib/sessions/models.py +++ b/baph/contrib/sessions/models.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from sqlalchemy import * from baph.db.orm import ORM diff --git a/baph/contrib/staticfiles/finders.py b/baph/contrib/staticfiles/finders.py index 0b5c224..297d014 100644 --- a/baph/contrib/staticfiles/finders.py +++ b/baph/contrib/staticfiles/finders.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from collections import OrderedDict from glob import iglob from importlib import import_module diff --git a/baph/contrib/staticfiles/management/commands/collectstatic.py b/baph/contrib/staticfiles/management/commands/collectstatic.py index 3375819..57400c2 100644 --- a/baph/contrib/staticfiles/management/commands/collectstatic.py +++ b/baph/contrib/staticfiles/management/commands/collectstatic.py @@ -1,9 +1,12 @@ +from __future__ import absolute_import +from __future__ import print_function import os from collections import OrderedDict from django.contrib.staticfiles.finders import get_finders from django.contrib.staticfiles.storage import staticfiles_storage -print 'storage:', staticfiles_storage +from six.moves import input +print('storage:', staticfiles_storage) from django.core.files.storage import FileSystemStorage from django.core.management.color import no_style @@ -180,7 +183,7 @@ def handle(self, **options): 'Are you sure you want to do this?\n\n' "Type 'yes' to continue, or 'no' to cancel: " ) - if raw_input(''.join(message)) != 'yes': + if input(''.join(message)) != 'yes': raise CommandError("Collecting static files cancelled.") collected = self.collect() diff --git a/baph/contrib/staticfiles/management/commands/findstatic.py b/baph/contrib/staticfiles/management/commands/findstatic.py index 9466c2f..b3c7ff9 100644 --- a/baph/contrib/staticfiles/management/commands/findstatic.py +++ b/baph/contrib/staticfiles/management/commands/findstatic.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os from baph.contrib.staticfiles import finders diff --git a/baph/contrib/staticfiles/storage.py b/baph/contrib/staticfiles/storage.py index b8ba708..ab051b4 100644 --- a/baph/contrib/staticfiles/storage.py +++ b/baph/contrib/staticfiles/storage.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from django.contrib.staticfiles.utils import check_settings from django.core.exceptions import ImproperlyConfigured diff --git a/baph/core/cache/backends/memcached.py b/baph/core/cache/backends/memcached.py index 7db3750..c5d42fa 100644 --- a/baph/core/cache/backends/memcached.py +++ b/baph/core/cache/backends/memcached.py @@ -1,6 +1,193 @@ +from collections import defaultdict +from functools import partial +import operator import time +from cached_property import cached_property from django.core.cache.backends.memcached import MemcachedCache +from six.moves import map, reduce +from six.moves.urllib.parse import unquote + + +KEY_VALUE_SPLITTER = operator.methodcaller('split', '=', 1) + +def parse_metadump(line): + # line format: =* + split = operator.methodcaller('split', '=', 1) + + data = dict(list(map(KEY_VALUE_SPLITTER, line))) + data['key'] = unquote(data['key']) + return data + +def parse_cachedump(line, **kwargs): + data = dict(kwargs) + key, metadata = line + data['key'] = key #.encode('utf8') + metadata = metadata[1:-1] # strip brackets + for key in ('size', 'exp'): + stat, sep, metadata = metadata.partition(';') + value, unit = stat.strip().split(' ', 1) + data[key] = int(value) + return data + +def parse_stat(line): + # line format: STAT + return (line[1], line[2]) + + +class MemcacheServer(object): + def __init__(self, server): + self.server = server + + @cached_property + def settings(self): + return dict(self.get_stats('settings')) + + @cached_property + def slabs(self): + return self.get_slabs() + + def send_command(self, cmd, row_len=0, expect=None): + """ + send a command to the server, and returns a parsed response + + the response is a list of lines + each line in the list is a list of space-delimited strings + """ + if not self.server.connect(): + return + self.server.send_cmd(cmd) + if expect: + self.server.expect(expect) + return None + lines = [] + while True: + line = self.server.readline() + if not line: + break + line = line.decode('ascii').strip() + while line: + # readline splits on '\r\n', we still need to split on '\n' + item, sep, line = line.partition('\n') + if item == 'END': + return lines + else: + lines.append(item.split(' ', row_len-1)) + return lines + + # command implementations + + def flush_all(self): + """ + flushes all keys in the cache + + returns None + """ + cmd = 'flush_all' + return self.send_command(cmd, expect='OK') + #self.delete_many_raw(self.get_keys()) + + def delete_many_raw(self, keys): + """ + Deletes the specified keys (does not run them through make_key) + """ + self.server._cache.delete_multi(keys) + + def get_metadump(self, slab_id): + cmd = 'lru_crawler metadump %s' % slab_id + return list(map(parse_metadump, self.send_command(cmd))) + + def get_stats(self, *args): + """ + returns a list of (key, value) tuples for a stats command + """ + cmd = ' '.join(('stats',) + args) + return list(map(parse_stat, self.send_command(cmd, 3))) + + + # STATS command variants + + def get_slabs(self): + """ + gets configuration settings for active slabs + """ + slabs = defaultdict(dict) + for key, value in self.get_stats('items'): + # key format: items:: + _, slab_id, key = key.split(':', 2) + slabs[slab_id][key] = value + return slabs + + def get_slab_stats(self): + """ + gets statistics for active slabs + """ + slab_stats = defaultdict(dict) + for key, value in self.get_stats('slabs'): + # key format 1: : + # key format 2: + if ':' in key: + slab_id, key = key.split(':') + else: + slab_id = 'totals' + slab_stats[slab_id][key] = value + return slab_stats + + def get_cachedump(self, slab_id, limit): + limit = limit or 0 + cmd = 'cachedump %s %s' % (slab_id, limit) + return list(map(parse_cachedump, self.get_stats(cmd))) + + def get_slab_keys_from_metadump(self, slab_id, limit=None): + """ + returns all keys in a slab using 'lru_crawler metadump' + """ + # metadump doesn't support a limit param, so we need to handle it + items = self.get_metadump(slab_id) + return items[:limit] + + def get_slab_keys_from_cachedump(self, slab_id, limit=None): + """ + returns all keys in a slab using 'stats cachedump' + """ + return self.get_cachedump(slab_id, limit) + + def get_slab_keys(self, slab_id, limit=None): + """ + returns all keys in a slab, as a list of dicts + """ + if self.settings.get('lru_crawler', 'no') == 'yes': + return self.get_slab_keys_from_metadump(slab_id, limit) + else: + return self.get_slab_keys_from_cachedump(slab_id, limit) + + def get_keys_from_metadump(self, limit=None): + """ + returns all keys on the server using 'lru_crawler metadump' + """ + return self.get_slab_keys_from_metadump('all', limit) + + def get_keys_from_cachedump(self, limit=None): + """ + returns all keys on the server using 'stats cachedump' + """ + func = partial(self.get_slab_keys_from_cachedump, limit=limit) + return reduce(operator.concat, list(map(func, self.slabs))) + + def get_keys(self, limit=None, include_expired=False): + """ + returns all keys on the server, as a list of strings + """ + if self.settings.get('lru_crawler', 'no') == 'yes': + func = self.get_keys_from_metadump + else: + func = self.get_keys_from_cachedump + getter = operator.itemgetter('key') + ts = time.time() + items = func(limit) + if not include_expired: + items = filter(lambda x: float(x['exp']) > ts, items) + return map(getter, items) class BaphMemcachedCache(MemcachedCache): @@ -10,57 +197,26 @@ class BaphMemcachedCache(MemcachedCache): def __init__(self, server, params): super(BaphMemcachedCache, self).__init__(server, params) self.version = params.get('VERSION', 0) + self.alias = params.get('ALIAS', None) - def delete_many_raw(self, keys): - """ - Deletes the specified keys (does not run them through make_key) - """ - self._cache.delete_multi(keys) + def __str__(self): + return '' % self.alias - def flush_all(self): - for s in self._cache.servers: - if not s.connect(): continue - s.send_cmd('flush_all') - s.expect("OK") - self.delete_many_raw(self.get_server_keys(s)) + @cached_property + def servers(self): + return list(map(MemcacheServer, self._cache.servers)) def get_all_keys(self): keys = set() - for s in self._cache.servers: - keys.update(self.get_server_keys(s)) + for server in self.servers: + try: + del server.slabs # force rebuild of slab ids if cached + except AttributeError: + pass + keys.update(server.get_keys()) return keys - def get_server_keys(self, s): - keys = set() - slab_ids = self.get_server_slab_ids(s) - for slab_id in slab_ids: - keys.update(self.get_slab_keys(s, slab_id)) - return keys - - def get_slab_keys(self, s, slab_id): - keys = set() - s.send_cmd('stats cachedump %s 100' % slab_id) - readline = s.readline - ts = time.time() - while 1: - line = readline() - if not line or line.strip() == 'END': break - frags = line.split(' ') - key = frags[1] - expire = int(frags[4]) - if expire > ts: - keys.add(key) - return keys - - def get_server_slab_ids(self, s): - if not s.connect(): - return set() - slab_ids = set() - s.send_cmd('stats items') - readline = s.readline - while 1: - line = readline() - if not line or line.strip() == 'END': break - frags = line.split(':') - slab_ids.add(frags[1]) - return slab_ids + def flush_all(self): + self.clear() + #for server in self.servers: + # server.flush_all() diff --git a/baph/core/cache/utils.py b/baph/core/cache/utils.py index aa514e9..e5ff323 100644 --- a/baph/core/cache/utils.py +++ b/baph/core/cache/utils.py @@ -1,5 +1,7 @@ +from __future__ import absolute_import from contextlib import contextmanager import time +import six try: @@ -108,7 +110,7 @@ def get_default(self): return self.default_value if self.default_func is None: return None - if isinstance(self.default_func, basestring): + if isinstance(self.default_func, six.string_types): self.default_func = import_string(self.default_func) if not callable(self.default_func): raise Exception('default_func %r is not callable') diff --git a/baph/core/files/storage.py b/baph/core/files/storage.py index 5dc4a83..d4a20df 100644 --- a/baph/core/files/storage.py +++ b/baph/core/files/storage.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from django.core.files import storage from django.utils import timezone diff --git a/baph/core/handlers/base.py b/baph/core/handlers/base.py index bf91f4e..babd194 100644 --- a/baph/core/handlers/base.py +++ b/baph/core/handlers/base.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals +from __future__ import absolute_import import logging import sys import types @@ -17,7 +18,7 @@ convert_exception_to_response, get_exception_response, handle_uncaught_exception, ) -from utils import get_resolver +from .utils import get_resolver logger = logging.getLogger('django.request') diff --git a/baph/core/handlers/exception.py b/baph/core/handlers/exception.py index 7c134c8..8a3daba 100644 --- a/baph/core/handlers/exception.py +++ b/baph/core/handlers/exception.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals +from __future__ import absolute_import import logging import sys import warnings diff --git a/baph/core/handlers/proxy.py b/baph/core/handlers/proxy.py index 77a26d4..9ea63de 100644 --- a/baph/core/handlers/proxy.py +++ b/baph/core/handlers/proxy.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.core.urlresolvers import set_urlconf, RegexURLPattern from baph.utils.module_loading import import_string diff --git a/baph/core/handlers/utils.py b/baph/core/handlers/utils.py index 697a95d..130ec37 100644 --- a/baph/core/handlers/utils.py +++ b/baph/core/handlers/utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.core.urlresolvers import RegexURLResolver diff --git a/baph/core/management/__init__.py b/baph/core/management/__init__.py index 88550c7..cf66b2d 100644 --- a/baph/core/management/__init__.py +++ b/baph/core/management/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from argparse import ArgumentParser from collections import defaultdict, OrderedDict import os diff --git a/baph/core/management/base.py b/baph/core/management/base.py index 125c6e3..bb8189e 100644 --- a/baph/core/management/base.py +++ b/baph/core/management/base.py @@ -3,7 +3,7 @@ be executed through ``django-admin.py`` or ``manage.py``). """ -from cStringIO import StringIO +from __future__ import absolute_import from optparse import make_option, OptionParser import os import sys @@ -13,7 +13,7 @@ from django.core.exceptions import ImproperlyConfigured from django.core.management.color import color_style #from django.utils.encoding import force_str -#from django.utils.six import StringIO +from django.utils.six import StringIO from baph.core.preconfig.loader import PreconfigLoader diff --git a/baph/core/management/commands/dumpdata.py b/baph/core/management/commands/dumpdata.py index ef707f8..29af2da 100644 --- a/baph/core/management/commands/dumpdata.py +++ b/baph/core/management/commands/dumpdata.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from optparse import make_option from django.core.exceptions import ImproperlyConfigured @@ -91,7 +92,7 @@ def handle(self, *app_labels, **options): if model is None: raise CommandError("Unknown model: %s.%s" % (app_label, model_label)) - if app in app_list.keys(): + if app in list(app_list.keys()): if app_list[app] and model not in app_list[app]: app_list[app].append(model) else: @@ -110,7 +111,7 @@ def handle(self, *app_labels, **options): def get_objects(): # Collate the objects to be serialized. session = orm.sessionmaker() - for model in sort_dependencies(app_list.items()): + for model in sort_dependencies(list(app_list.items())): if model in excluded_models: continue for obj in session.query(model): diff --git a/baph/core/management/commands/dumpsettings.py b/baph/core/management/commands/dumpsettings.py index 8516054..2f7789a 100644 --- a/baph/core/management/commands/dumpsettings.py +++ b/baph/core/management/commands/dumpsettings.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function import json import pprint @@ -51,7 +53,7 @@ def handle(self, *keys, **options): if len(settings) != 1: raise CommandError('--scalar can only be used when requesting ' 'a single setting') - output = json.dumps(settings.values().pop()) + output = json.dumps(list(settings.values()).pop()) else: # return a dict of key/value pairs output = json.dumps(settings, sort_keys=True) @@ -59,4 +61,4 @@ def handle(self, *keys, **options): if pretty: pprint.pprint(output) else: - print output + print(output) diff --git a/baph/core/management/commands/flush.py b/baph/core/management/commands/flush.py index fc538dc..c06beae 100644 --- a/baph/core/management/commands/flush.py +++ b/baph/core/management/commands/flush.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from optparse import make_option from django.conf import settings @@ -10,6 +11,7 @@ from baph.core.management.sql import emit_post_sync_signal from baph.db import ORM, DEFAULT_DB_ALIAS from baph.db.models import signals, get_apps, get_models +from six.moves import input orm = ORM.get() @@ -48,7 +50,7 @@ def handle(self, **options): #sql_list = sql_flush(self.style, connection, only_django=True) if interactive: - confirm = raw_input("""You have requested a flush of the database. + confirm = input("""You have requested a flush of the database. This will IRREVERSIBLY DESTROY all data currently in the database, and return each table to the state it was in after syncdb. Are you sure you want to do this? diff --git a/baph/core/management/commands/killcache.py b/baph/core/management/commands/killcache.py index 9d01c03..d1071d5 100644 --- a/baph/core/management/commands/killcache.py +++ b/baph/core/management/commands/killcache.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from collections import defaultdict import json import os @@ -10,11 +12,11 @@ from sqlalchemy import * from sqlalchemy.exc import ResourceClosedError from sqlalchemy.orm import lazyload, contains_eager, class_mapper -from sqlalchemy.orm.util import identity_key from sqlalchemy.sql import compiler from baph.core.management.base import BaseCommand #NoArgsCommand from baph.db.orm import ORM +from six.moves import input success_msg = make_style(fg='green') @@ -34,35 +36,35 @@ def get_cacheable_models(): yield k def lookup_model(): - name = raw_input('Enter model name ("L" to list): ') + name = input('Enter model name ("L" to list): ') name = name.lower() for k,v in Base._decl_class_registry.items(): if k.startswith('_'): continue if name == 'l': - print '\t%s' % k, v._meta.cache_detail_keys + print('\t%s' % k, v._meta.cache_detail_keys) if name == k.lower(): return v if name != 'l': - print 'Invalid choice: %s' % name + print('Invalid choice: %s' % name) def prompt_for_model_name(): while True: - cmd = raw_input('\nKill cache for which model? ' + cmd = input('\nKill cache for which model? ' '(ENTER to list, Q to quit): ') if cmd in ('q', 'Q'): return None if not cmd: for name in get_cacheable_models(): - print ' %s' % name + print(' %s' % name) continue return cmd def prompt_for_pk(model): - print 'Enter the primary key components:' + print('Enter the primary key components:') pk = [] for col in class_mapper(model).primary_key: - v = raw_input(' %s: ' % col.name) + v = input(' %s: ' % col.name) pk.append(v) return tuple(pk) @@ -82,7 +84,7 @@ def handle(self, *args, **options): else: pks = None - print '' + print('') while True: if not model_name: model_name = prompt_for_model_name() @@ -90,7 +92,7 @@ def handle(self, *args, **options): # quit break if not model_name in Base._decl_class_registry: - print error_msg('Invalid model name: %s' % model_name) + print(error_msg('Invalid model name: %s' % model_name)) model_name = None continue model = Base._decl_class_registry[model_name] @@ -101,13 +103,13 @@ def handle(self, *args, **options): session = orm.sessionmaker() for pk in pks: - print info_msg('\nLooking up %r with pk=%s' % (model_name, pk)) + print(info_msg('\nLooking up %r with pk=%s' % (model_name, pk))) obj = session.query(model).get(pk) if not obj: - print error_msg(' No %s found with PK %s' % (model_name, pk)) + print(error_msg(' No %s found with PK %s' % (model_name, pk))) continue - print success_msg(' Found object: %r' % obj) + print(success_msg(' Found object: %r' % obj)) caches = defaultdict(lambda: { 'cache_keys': set(), @@ -125,13 +127,13 @@ def handle(self, *args, **options): caches[alias]['version_keys'].add(version_key) for alias, keys in caches.items(): - print info_msg('Processing keys on cache %r' % alias) + print(info_msg('Processing keys on cache %r' % alias)) cache = get_cache(alias) for key in keys['cache_keys']: - print ' Killing cache key: %r' % key + print(' Killing cache key: %r' % key) cache.delete_many(keys['cache_keys']) for key in keys['version_keys']: - print ' Incrementing version key: %r' % key + print(' Incrementing version key: %r' % key) cache.incr(key) model_name = None diff --git a/baph/core/management/commands/loaddata.py b/baph/core/management/commands/loaddata.py index 2ef98f8..c92131f 100644 --- a/baph/core/management/commands/loaddata.py +++ b/baph/core/management/commands/loaddata.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from __future__ import absolute_import import glob import gzip from itertools import product @@ -26,11 +27,11 @@ from django.utils.functional import cached_property, memoize from sqlalchemy.orm.attributes import instance_dict from sqlalchemy.orm.session import Session -from sqlalchemy.orm.util import identity_key from baph.core.management.new_base import BaseCommand from baph.db import DEFAULT_DB_ALIAS from baph.db.models import get_app_paths +from baph.db.models.utils import identity_key from baph.db.orm import ORM from baph.utils.glob import glob_escape @@ -228,8 +229,7 @@ def load_label(self, fixture_label): if True: #router.allow_syncdb(self.using, obj.object.__class__): loaded_objects_in_fixture += 1 self.models.add(type(obj)) - ident = identity_key(instance=obj) - (cls, key) = ident[:2] + (cls, key) = identity_key(instance=obj) if any(part is None for part in key): # we can't generate an explicit key with this info session.add(obj) diff --git a/baph/core/management/commands/nsincr.py b/baph/core/management/commands/nsincr.py index 7db9c42..e0a3ad9 100644 --- a/baph/core/management/commands/nsincr.py +++ b/baph/core/management/commands/nsincr.py @@ -1,5 +1,8 @@ +from __future__ import absolute_import +from __future__ import print_function from baph.core.cache.utils import CacheNamespace from baph.core.management.base import NoArgsCommand +from six.moves import input def build_options_list(namespaces): @@ -15,16 +18,16 @@ def build_options_list(namespaces): return options def print_options(options): - print '\n%s %s %s' % ('id', 'name'.ljust(16), 'attrs') + print('\n%s %s %s' % ('id', 'name'.ljust(16), 'attrs')) for i, (ns, name, attr, type, models) in enumerate(options): names = sorted([model.__name__ for model in models]) - print '%s %s %s' % (i, name.ljust(16), attr) - print ' invalidates: %s' % names + print('%s %s %s' % (i, name.ljust(16), attr)) + print(' invalidates: %s' % names) def get_value_for_attr(attr): msg = 'Enter the value for %r (ENTER to cancel): ' % attr while True: - value = raw_input(msg).strip() + value = input(msg).strip() if not value: return None return value @@ -33,7 +36,7 @@ def get_option(options): name_map = {opt[1].lower(): i for i, opt in enumerate(options)} msg = '\nIncrement which ns key? (ENTER to list, Q to quit): ' while True: - value = raw_input(msg).strip().lower() + value = input(msg).strip().lower() if not value: print_options(options) continue @@ -49,22 +52,22 @@ def get_option(options): # string reference index = name_map[value] else: - print 'Invalid option: %r' % value + print('Invalid option: %r' % value) continue if index >= len(options): - print 'Invalid index: %r' % index + print('Invalid index: %r' % index) continue return options[index] def increment_version_key(cache, key): version = cache.get(key) - print ' current value of %s: %s' % (key, version) + print(' current value of %s: %s' % (key, version)) version = version + 1 if version else 1 cache.set(key, version) version = cache.get(key) - print ' new value of %s: %s' % (key, version) + print(' new value of %s: %s' % (key, version)) class Command(NoArgsCommand): @@ -115,7 +118,7 @@ def handle_noargs(self, **options): try: result = self.main() except KeyboardInterrupt: - print '' + print('') break if result is None: break diff --git a/baph/core/management/commands/purge.py b/baph/core/management/commands/purge.py index ab3f3c4..ef16110 100644 --- a/baph/core/management/commands/purge.py +++ b/baph/core/management/commands/purge.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import print_function from copy import deepcopy from optparse import make_option import sys @@ -22,6 +24,7 @@ from baph.db import DEFAULT_DB_ALIAS from baph.db.models import signals, get_apps, get_models from baph.db.orm import ORM +from six.moves import input post_syncdb = Signal(providing_args=["class", "app", "created_models", @@ -92,13 +95,13 @@ def handle(self, **options): db_info = orm.settings_dict is_test_db = db_info.get('TEST', False) if not is_test_db: - print 'Database "%s" cannot be purged because it is not a test ' \ + print('Database "%s" cannot be purged because it is not a test ' \ 'database.\nTo flag this as a test database, set TEST to ' \ - 'True in the database settings.' % db + 'True in the database settings.' % db) sys.exit() if interactive: - confirm = raw_input('\nYou have requested a purge of database ' \ + confirm = input('\nYou have requested a purge of database ' \ '"%s" (%s). This will IRREVERSIBLY DESTROY all data ' \ 'currently in the database, and DELETE ALL TABLES AND ' \ 'SCHEMAS. Are you sure you want to do this?\n\n' \ diff --git a/baph/core/management/commands/runserver.py b/baph/core/management/commands/runserver.py index 94247ff..d918aba 100644 --- a/baph/core/management/commands/runserver.py +++ b/baph/core/management/commands/runserver.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from cStringIO import StringIO import mimetools diff --git a/baph/core/management/commands/shell.py b/baph/core/management/commands/shell.py index 432115f..aed7383 100644 --- a/baph/core/management/commands/shell.py +++ b/baph/core/management/commands/shell.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os from optparse import make_option diff --git a/baph/core/management/commands/syncdb.py b/baph/core/management/commands/syncdb.py index b78a199..b5e91ef 100644 --- a/baph/core/management/commands/syncdb.py +++ b/baph/core/management/commands/syncdb.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import print_function from optparse import make_option import traceback @@ -163,13 +165,13 @@ def handle_noargs(self, **options): all_tables.index(get_tablename(x[1]))) if verbosity >= 3: - print 'Schema Manifest:\n' + print('Schema Manifest:\n') for schema in schema_manifest: - print '\t%s\n' % schema - print 'Model/Table Manifest\n' + print('\t%s\n' % schema) + print('Model/Table Manifest\n') for app_name, model in table_manifest: - print '\t%s.%s (%s)\n' % (app_name, model._meta.object_name, - get_tablename(model)) + print('\t%s.%s (%s)\n' % (app_name, model._meta.object_name, + get_tablename(model))) # create any missing schemas if verbosity >= 1: diff --git a/baph/core/management/commands/tables.py b/baph/core/management/commands/tables.py index 495df41..2ff705c 100644 --- a/baph/core/management/commands/tables.py +++ b/baph/core/management/commands/tables.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from baph.db.orm import ORM from django.core.management.base import BaseCommand @@ -13,5 +15,5 @@ def handle(self, *args, **options): tables = [(table.schema or default_schema, table.name) for table in Base.metadata.tables.values()] for table in sorted(tables): - print '.'.join(table) + print('.'.join(table)) diff --git a/baph/core/management/commands/test.py b/baph/core/management/commands/test.py index 7a25e51..9915c47 100644 --- a/baph/core/management/commands/test.py +++ b/baph/core/management/commands/test.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import logging import sys import os diff --git a/baph/core/management/commands/validate.py b/baph/core/management/commands/validate.py index d34b064..d42f063 100644 --- a/baph/core/management/commands/validate.py +++ b/baph/core/management/commands/validate.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from sqlalchemy.orm import configure_mappers from baph.core.management.base import NoArgsCommand @@ -15,9 +17,9 @@ def handle_noargs(self, **options): self.validate(display_num_errors=True) #configure_mappers() - print '\nPost-Validation Tables:' + print('\nPost-Validation Tables:') for table in Base.metadata.tables: - print '\t', table + print('\t', table) """ print '\nPost-Validation Class Registry:' for k,v in sorted(Base._decl_class_registry.items()): diff --git a/baph/core/management/new_base.py b/baph/core/management/new_base.py index abd1a3a..f3e800f 100644 --- a/baph/core/management/new_base.py +++ b/baph/core/management/new_base.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import inspect import os import sys @@ -14,6 +15,7 @@ from baph.core.preconfig.loader import PreconfigLoader from baph.core.management.utils import get_command_options, get_parser_options from .base import CommandError +from six.moves import zip LEGACY_OPT_KWARGS = ('nargs', 'help', 'action', 'dest', 'default', @@ -143,7 +145,7 @@ def get_legacy_kwargs(self): for option in self.option_list: args = option._long_opts + option._short_opts getter = attrgetter(*LEGACY_OPT_KWARGS) - kwargs = dict(zip(LEGACY_OPT_KWARGS, getter(option))) + kwargs = dict(list(zip(LEGACY_OPT_KWARGS, getter(option)))) if kwargs.get('type', None): kwargs['type'] = LEGACY_OPT_TYPES[kwargs['type']] kwargs = {k: v for k, v in kwargs.items() if v is not None} diff --git a/baph/core/management/sql.py b/baph/core/management/sql.py index 5c0da38..3779b6b 100644 --- a/baph/core/management/sql.py +++ b/baph/core/management/sql.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from baph.db.models import signals, get_apps from baph.db.orm import ORM, Base @@ -7,7 +9,7 @@ def emit_post_sync_signal(created_models, verbosity, interactive, db): for app in get_apps(): app_name = app.__name__.rsplit('.',1)[0] if verbosity >= 2: - print("Running post-sync handlers for application %s" % app_name) + print(("Running post-sync handlers for application %s" % app_name)) signals.post_syncdb.send(sender=app, app=app, created_models=created_models, verbosity=verbosity, interactive=interactive, db=db) diff --git a/baph/core/management/validation.py b/baph/core/management/validation.py index c485b44..7b90351 100644 --- a/baph/core/management/validation.py +++ b/baph/core/management/validation.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import collections import sys diff --git a/baph/core/preconfig/__init__.py b/baph/core/preconfig/__init__.py index 8e0a129..aacec0c 100644 --- a/baph/core/preconfig/__init__.py +++ b/baph/core/preconfig/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os from .loader import PreconfigLoader diff --git a/baph/core/preconfig/config.py b/baph/core/preconfig/config.py index 5db7e51..46c7c05 100644 --- a/baph/core/preconfig/config.py +++ b/baph/core/preconfig/config.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import argparse from functools import partial import itertools @@ -9,6 +10,8 @@ from baph.utils.collections import flatten from .options import PackageOption, ModuleOption from .utils import with_empty +from six.moves import map +from six.moves import range def templatize(key): @@ -115,7 +118,7 @@ def package_metavars(self): @property def package_tpls(self): " returns the package name templates " - packages = [self.package] + map(templatize, self.package_args) + packages = [self.package] + list(map(templatize, self.package_args)) return packages @property @@ -222,7 +225,8 @@ def load_options(self, data): else: raise ValueError('Invalid scope %r (must be "package" or "module")') self.arg_map[name] = opt - self.module_options = sorted(modules, key=lambda x: x.order) + + self.module_options = sorted(modules, key=lambda x: str(x.order)) self.package_options = packages def add_to_parser(self, parser): diff --git a/baph/core/preconfig/loader.py b/baph/core/preconfig/loader.py index 119dffe..248e77d 100644 --- a/baph/core/preconfig/loader.py +++ b/baph/core/preconfig/loader.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import imp import inspect import os diff --git a/baph/core/preconfig/utils.py b/baph/core/preconfig/utils.py index 24c2c18..c33ff07 100644 --- a/baph/core/preconfig/utils.py +++ b/baph/core/preconfig/utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import imp import os diff --git a/baph/core/serializers/base.py b/baph/core/serializers/base.py index d062330..13641f8 100644 --- a/baph/core/serializers/base.py +++ b/baph/core/serializers/base.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.core.serializers.base import Serializer as BaseSerializer from django.utils import six from sqlalchemy import inspect diff --git a/baph/core/serializers/json.py b/baph/core/serializers/json.py index c17287e..e9ef5ef 100644 --- a/baph/core/serializers/json.py +++ b/baph/core/serializers/json.py @@ -1,9 +1,6 @@ from __future__ import absolute_import from __future__ import unicode_literals -from StringIO import StringIO -import datetime -import decimal import json import sys @@ -11,7 +8,7 @@ from baph.core.serializers.python import Deserializer as PythonDeserializer from django.core.serializers.base import DeserializationError from django.core.serializers.json import DjangoJSONEncoder -from django.utils import six +import six class Serializer(PythonSerializer): @@ -57,6 +54,7 @@ def getvalue(self): # Grand-parent super return super(PythonSerializer, self).getvalue() + def Deserializer(stream_or_string, **options): """ Deserialize a stream or string of JSON data. diff --git a/baph/core/serializers/python.py b/baph/core/serializers/python.py index f496b91..1cfc29d 100644 --- a/baph/core/serializers/python.py +++ b/baph/core/serializers/python.py @@ -1,10 +1,13 @@ -from django.utils.encoding import smart_text, is_protected_type -from sqlalchemy.orm.util import identity_key +from __future__ import absolute_import + +import six from baph.core.serializers import base from baph.db import DEFAULT_DB_ALIAS from baph.db.models import get_apps +from baph.db.models.utils import identity_key from baph.db.orm import Base +from baph.utils.encoding import smart_unicode class Serializer(base.Serializer): @@ -54,8 +57,8 @@ def Deserializer(object_list, **options): #m2m_data = {} # Handle each field - for (field_name, field_value) in d.iteritems(): - if isinstance(field_value, str): + for (field_name, field_value) in six.iteritems(d): + if isinstance(field_value, bytes): field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True) @@ -63,6 +66,7 @@ def Deserializer(object_list, **options): yield Model(**data) + def _get_model(model_identifier): """ Helper to look up a model from an "app_label.module_name" string. diff --git a/baph/core/validators.py b/baph/core/validators.py index d34e44a..1b2258c 100644 --- a/baph/core/validators.py +++ b/baph/core/validators.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import from django.core import validators +import six class MaxLengthValidator(validators.MaxLengthValidator): def clean(self, content): - if isinstance(content, unicode): + if isinstance(content, six.text_type): return len(content.encode('utf8')) else: return len(content) diff --git a/baph/core/wsgi.py b/baph/core/wsgi.py index df988bc..9a37844 100644 --- a/baph/core/wsgi.py +++ b/baph/core/wsgi.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import baph from django.core.handlers.wsgi import WSGIHandler diff --git a/baph/db/__init__.py b/baph/db/__init__.py index c6f4ce1..aa93a99 100644 --- a/baph/db/__init__.py +++ b/baph/db/__init__.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from django.core import signals from django.core.exceptions import ImproperlyConfigured diff --git a/baph/db/backends/__init__.py b/baph/db/backends/__init__.py index a791eb2..1dd1d79 100644 --- a/baph/db/backends/__init__.py +++ b/baph/db/backends/__init__.py @@ -44,7 +44,7 @@ def django_config_to_sqla_config(config): 'database': config.get('NAME', None), 'query': config.get('OPTIONS', None), } - for k, v in params.items(): + for k, v in list(params.items()): if not v: del params[k] return params diff --git a/baph/db/encodings/mysql.py b/baph/db/encodings/mysql.py index 58ee546..ed266ec 100644 --- a/baph/db/encodings/mysql.py +++ b/baph/db/encodings/mysql.py @@ -2,6 +2,7 @@ """#" +from __future__ import absolute_import import codecs ### Codec APIs diff --git a/baph/db/management/commands/syncsqlalchemy.py b/baph/db/management/commands/syncsqlalchemy.py index eb2a2b2..a598270 100644 --- a/baph/db/management/commands/syncsqlalchemy.py +++ b/baph/db/management/commands/syncsqlalchemy.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.orm import ORM from baph.utils.importing import import_any_module from django.conf import settings diff --git a/baph/db/models/__init__.py b/baph/db/models/__init__.py index 5110d59..0eedbb3 100644 --- a/baph/db/models/__init__.py +++ b/baph/db/models/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.models import signals from baph.db.models.loading import (get_apps, get_app, get_models, get_model, get_app_errors, register_models, get_app_paths) diff --git a/baph/db/models/base.py b/baph/db/models/base.py index aeae760..7abd177 100644 --- a/baph/db/models/base.py +++ b/baph/db/models/base.py @@ -16,7 +16,7 @@ from sqlalchemy.orm.interfaces import MANYTOONE from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty from sqlalchemy.orm.session import Session -from sqlalchemy.orm.util import has_identity, identity_key +from sqlalchemy.orm.util import has_identity from sqlalchemy.schema import ForeignKeyConstraint from baph.db import ORM @@ -24,10 +24,12 @@ from baph.db.models.loading import get_model, register_models from baph.db.models.mixins import CacheMixin, GlobalMixin, ModelPermissionMixin from baph.db.models.options import Options -from baph.db.models.utils import key_to_value +from baph.db.models.utils import key_to_value, identity_key from baph.utils.functional import cachedclassproperty from baph.utils.importing import remove_class from baph.utils.module_loading import import_string +import six +from six.moves import zip @compiles(ForeignKeyConstraint) @@ -70,9 +72,13 @@ def constructor(self, **kwargs): continue default = col.default.arg if callable(default): - setattr(self, attr.key, default({})) + value = default({}) else: - setattr(self, attr.key, default) + value = default + # set defaults directly to self.__dict__ to avoid triggering + # event listeners + #self.__dict__[attr.key] = value + setattr(self, attr.key, value) # now load in the kwargs values for k in kwargs: @@ -150,16 +156,14 @@ def before_flush_attrs(cls): def pk_as_query_filters(self, force=False): " returns a filter expression for the primary key of the instance " " suitable for use with Query.filter() " - ident = identity_key(instance=self) - (cls, pk_values) = ident[:2] - + (cls, pk_values) = identity_key(instance=self) if None in pk_values and not force: return None - items = zip(self.pk_attrs, pk_values) + items = list(zip(self.pk_attrs, pk_values)) return and_(attr == value for attr, value in items) def update(self, data): - for key, value in data.iteritems(): + for key, value in six.iteritems(data): if hasattr(self, key) and getattr(self, key) != value: setattr(self, key, value) @@ -187,7 +191,7 @@ def to_dict(self): :rtype: :class:`dict` ''' - __dict__ = dict([(key, val) for key, val in self.__dict__.iteritems() + __dict__ = dict([(key, val) for key, val in six.iteritems(self.__dict__) if not key.startswith('_sa_')]) if len(__dict__) == 0: for attr in inspect(type(self)).column_attrs: @@ -274,7 +278,7 @@ def __init__(cls, name, bases, attrs): registry = cls._decl_class_registry if name in registry: found = True - elif cls in registry.values(): + elif cls in list(registry.values()): found = True add_class(name, cls) diff --git a/baph/db/models/cloning.py b/baph/db/models/cloning.py index 3088fdc..c938994 100644 --- a/baph/db/models/cloning.py +++ b/baph/db/models/cloning.py @@ -1,15 +1,18 @@ +from __future__ import absolute_import import copy -from sqlalchemy import inspect +from sqlalchemy import inspect, Column from sqlalchemy.orm import class_mapper from sqlalchemy.orm.attributes import instance_dict from sqlalchemy.orm.collections import MappedCollection from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty from sqlalchemy.orm.session import object_session -from sqlalchemy.orm.util import identity_key +from baph.db.models.utils import identity_key from baph.db.orm import ORM from baph.utils.collections import duck_type_collection +from six.moves import map +from six.moves import zip orm = ORM.get() @@ -19,10 +22,10 @@ def reload_object(instance): """ Reloads an instance with the correct polymorphic subclass """ - cls, pk_vals = identity_key(instance=instance) + (cls, pk_vals) = identity_key(instance=instance) mapper = inspect(cls) pk_cols = [col.key for col in mapper.primary_key] - pk = dict(zip(pk_cols, pk_vals)) + pk = dict(list(zip(pk_cols, pk_vals))) session = object_session(instance) session.expunge(instance) instance = session.query(cls) \ @@ -38,7 +41,7 @@ def get_polymorphic_subclass(instance): the polymorphic map of the base class. for non-polymorphic classes, it returns the class """ - cls, pk = identity_key(instance=instance) + (cls, pk) = identity_key(instance=instance) base_mapper = inspect(cls) if base_mapper.polymorphic_on is None: # this is not a polymorphic class @@ -65,11 +68,18 @@ def get_cloning_rules(cls): def get_default_excludes(cls): """ - By default, exclude pks and fks + By default, exclude pks, fks, and query_expressions """ mapper = inspect(cls) + exclude_props = set() exclude_cols = set() + for attr in mapper.column_attrs: + # exclude column properties which do not refer to actual columns + # ie query_expressions + if not any(isinstance(col, Column) for col in attr.columns): + exclude_props.add(attr.key) + if mapper.polymorphic_on is not None: # do not copy the polymorphic discriminator. it will be set automatically # via the polymorphic class, and we don't want to generate flush warnings @@ -84,9 +94,9 @@ def get_default_excludes(cls): # do not copy foreign key columns exclude_cols.update(fkc.columns) - props = map(mapper.get_property_by_column, exclude_cols) + props = list(map(mapper.get_property_by_column, exclude_cols)) keys = set(prop.key for prop in props) - return keys + return exclude_props | keys def get_default_columns(cls): """ @@ -148,7 +158,7 @@ def get_rules(rules, rule_keys): def user_id(self): if not self.user: return None - cls, pk = identity_key(instance=self.user) + (cls, pk) = identity_key(instance=self.user) if len(pk) > 1: raise Exception('chown cannot used for multi-column user pks. To ' 'specify ownership for a user with a multi-column pk, add the ' @@ -218,8 +228,7 @@ def clone_collection(self, value, **kwargs): def clone_obj(self, instance, ruleset=None, rule_keys=None, cast_to=None): is_root = self.root is None - - base_cls, pk = identity_key(instance=instance) + (base_cls, pk) = identity_key(instance=instance) if (base_cls, pk) in self.registry: # we already cloned this return self.registry[(base_cls, pk)] diff --git a/baph/db/models/fields.py b/baph/db/models/fields.py index 0423696..b7aa97e 100644 --- a/baph/db/models/fields.py +++ b/baph/db/models/fields.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import collections from itertools import tee from types import FunctionType @@ -18,6 +19,7 @@ from baph.db import types from baph.forms import fields from baph.utils.collections import duck_type_collection +from six.moves import map def get_related_class_from_attr(attr): @@ -81,6 +83,21 @@ def __init__(self, verbose_name=None, name=None, primary_key=False, self.creation_counter = Field.creation_counter Field.creation_counter += 1 + def __eq__(self, other): + # Needed for @total_ordering + if isinstance(other, Field): + return self.creation_counter == other.creation_counter + return NotImplemented + + def __lt__(self, other): + # This is needed because bisect does not take a comparison function. + if isinstance(other, Field): + return self.creation_counter < other.creation_counter + return NotImplemented + + def __hash__(self): + return hash(self.creation_counter) + @property def unique(self): return self._unique or self.primary_key @@ -154,7 +171,7 @@ def formfield(self, form_class=None, **kwargs): if form_class is None: form_class = fields.NullCharField field = form_class(**defaults) - field.validators = map(self.modify_validator, field.validators) + field.validators = list(map(self.modify_validator, field.validators)) return field def clean(self, value): diff --git a/baph/db/models/files.py b/baph/db/models/files.py index baec19b..39fca7e 100644 --- a/baph/db/models/files.py +++ b/baph/db/models/files.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.core.files.images import ImageFile import hashlib diff --git a/baph/db/models/loading.py b/baph/db/models/loading.py index 4fcc5ae..6535f8e 100644 --- a/baph/db/models/loading.py +++ b/baph/db/models/loading.py @@ -214,7 +214,7 @@ def get_models(self, app_mod=None, include_auto_created=False, else: app_list = [] else: - app_list = self.app_models.values() + app_list = list(self.app_models.values()) """ if only_installed: app_list = [self.app_models.get(app_label, SortedDict()) diff --git a/baph/db/models/mixins.py b/baph/db/models/mixins.py index 07e7183..e4bc7af 100644 --- a/baph/db/models/mixins.py +++ b/baph/db/models/mixins.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from collections import defaultdict import datetime import logging @@ -15,10 +16,12 @@ from sqlalchemy.orm import class_mapper, object_session from sqlalchemy.orm.attributes import get_history, instance_dict from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty -from sqlalchemy.orm.util import has_identity, identity_key +from sqlalchemy.orm.util import has_identity from baph.db import ORM +from baph.db.models.utils import identity_key from .utils import column_to_attr, class_resolver +from six.moves import map cache_logger = logging.getLogger('cache') @@ -611,8 +614,7 @@ def get_cache_keys(self, child_updated=False, force_expire_pointers=False, # the fields which trigger this pointer were not changed continue cache_key = raw_key % data - ident_key = identity_key(instance=self) - _, ident = ident_key[:2] + (_, ident) = identity_key(instance=self) if len(ident) > 1: ident = ','.join(map(str, ident)) else: @@ -749,7 +751,7 @@ def get_fks(cls, include_parents=True, remote_key=None): if new_key in pairs: value = pairs[new_key] else: - primary_key, value = pairs.items()[0] + primary_key, value = list(pairs.items())[0] keys.append( (limiter, primary_key, value, col_key, cls_name) ) if not include_parents: diff --git a/baph/db/models/options.py b/baph/db/models/options.py index a5b36e2..397830c 100644 --- a/baph/db/models/options.py +++ b/baph/db/models/options.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import re from django.conf import settings @@ -15,6 +16,7 @@ from baph.db import types from baph.db.models.fields import Field from baph.utils.text import camel_case_to_spaces +import six DEFAULT_NAMES = ('model_name', 'model_name_plural', @@ -164,7 +166,7 @@ def contribute_to_class(self, cls, name): # Any leftover attributes must be invalid. if meta_attrs != {}: raise TypeError("'class Meta' got invalid attribute(s): %s" - % ','.join(meta_attrs.keys())) + % ','.join(list(meta_attrs.keys()))) # initialize params that depend on other params being set if self.model_name_plural is None: @@ -192,8 +194,8 @@ def contribute_to_class(self, cls, name): base_model_name = base._meta.base_model_name base_model_name_plural = base._meta.base_model_name_plural break - self.base_model_name = unicode(base_model_name) - self.base_model_name_plural = unicode(base_model_name_plural) + self.base_model_name = six.text_type(base_model_name) + self.base_model_name_plural = six.text_type(base_model_name_plural) del self.meta diff --git a/baph/db/models/properties.py b/baph/db/models/properties.py index 71e9c6f..47994ca 100644 --- a/baph/db/models/properties.py +++ b/baph/db/models/properties.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import itertools from django.template.defaultfilters import slugify @@ -8,6 +9,7 @@ from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty from sqlalchemy.orm.session import object_session from sqlalchemy.orm.util import has_identity +import six class AutoSlugField(ColumnProperty): @@ -19,7 +21,7 @@ def __init__(self, *args, **kwargs): self.populate_from = kwargs.pop('populate_from', None) self.index_sep = kwargs.pop('sep', '-') self.unique_with = kwargs.pop('unique_with', ()) - if isinstance(self.unique_with, basestring): + if isinstance(self.unique_with, six.string_types): self.unique_with = (self.unique_with,) self.slugify = kwargs.pop('slugify', slugify) diff --git a/baph/db/models/signals.py b/baph/db/models/signals.py index 452f914..8a52976 100644 --- a/baph/db/models/signals.py +++ b/baph/db/models/signals.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.dispatch import Signal class_prepared = Signal(providing_args=["class"]) diff --git a/baph/db/models/utils.py b/baph/db/models/utils.py index 28697b4..5ed99a7 100644 --- a/baph/db/models/utils.py +++ b/baph/db/models/utils.py @@ -1,9 +1,16 @@ +from __future__ import absolute_import import types from sqlalchemy import inspect from sqlalchemy.ext.declarative.clsregistry import _class_resolver +from sqlalchemy.orm.util import identity_key as new_identity_key +import six +def identity_key(*args, **kwargs): + """ returns a 2-tuple identity key, not the 3-tuple in newer SQLA """ + return new_identity_key(*args, **kwargs)[:2] + def has_inherited_table(cls): # TODO: a fix in sqla 0.9 should make this unnecessary, check it """ @@ -23,7 +30,7 @@ def class_resolver(cls): appropriate SQLA class """ from baph.db.orm import Base - if isinstance(cls, basestring): + if isinstance(cls, six.string_types): # string reference cls = Base._decl_class_registry[cls] if isinstance(cls, types.FunctionType): diff --git a/baph/db/orm.py b/baph/db/orm.py index c98bb3b..2e92779 100644 --- a/baph/db/orm.py +++ b/baph/db/orm.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from baph.db import ORM orm = ORM.get() Base = orm.Base diff --git a/baph/db/shortcuts.py b/baph/db/shortcuts.py index a0af331..c7dbf12 100644 --- a/baph/db/shortcuts.py +++ b/baph/db/shortcuts.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.orm import ORM from django.http import Http404 diff --git a/baph/db/types.py b/baph/db/types.py index b07436e..917c24a 100644 --- a/baph/db/types.py +++ b/baph/db/types.py @@ -6,6 +6,8 @@ .. moduleauthor:: Mark Lee .. moduleauthor:: Gerald Thibault ''' +from __future__ import absolute_import +import six try: import json except ImportError: @@ -82,7 +84,7 @@ def process_bind_param(self, value, dialect): if value is None: return None #return json.dumps(value) - return unicode(json.dumps(value)) + return six.text_type(json.dumps(value)) def process_result_value(self, value, dialect): if not value: @@ -191,7 +193,7 @@ def __init__(self, tz, *args, **kwargs): def process_bind_param(self, value, dialect): if value is None: return None - if isinstance(value, basestring): + if isinstance(value, six.string_types): value = value.replace('T', ' ').replace('Z', '+00:00') p = re.compile('([0-9: -]+)\.?([0-9]*)([\+-][0-9]{2}:?[0-9]{2})?') dt, ms, tz = p.match(value).groups() diff --git a/baph/db/utils.py b/baph/db/utils.py index fc6fd9f..7f915b2 100644 --- a/baph/db/utils.py +++ b/baph/db/utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf import settings from django.db.utils import ConnectionHandler diff --git a/baph/decorators/db.py b/baph/decorators/db.py index 7febf48..f381125 100644 --- a/baph/decorators/db.py +++ b/baph/decorators/db.py @@ -6,6 +6,7 @@ .. moduleauthor:: Mark Lee ''' +from __future__ import absolute_import from baph.db.orm import ORM from functools import wraps diff --git a/baph/decorators/json.py b/baph/decorators/json.py index cd46d55..5923d61 100644 --- a/baph/decorators/json.py +++ b/baph/decorators/json.py @@ -10,6 +10,7 @@ from __future__ import absolute_import from baph.utils.importing import import_any_module, import_attr +import six render_to_response = import_attr(['coffin.shortcuts'], 'render_to_response') from django.http import ( HttpResponse, HttpResponseRedirect, HttpResponseForbidden) @@ -68,7 +69,7 @@ class JSONify(object): def __init__(self, alternate_renderer=None, method=False, **kwargs): if alternate_renderer is None: self.renderer = self.render - elif isinstance(alternate_renderer, basestring): + elif isinstance(alternate_renderer, six.string_types): # assume Jinja2 template self.renderer = self.render_jinja self.template = alternate_renderer @@ -96,7 +97,7 @@ def method_handler(method_self, request, *args, **kwargs): return func_handler def _handler(self, data, request): - if isinstance(data, basestring): + if isinstance(data, six.string_types): data = { 'content': data, } diff --git a/baph/forms/fields.py b/baph/forms/fields.py index 465ead8..f36b728 100644 --- a/baph/forms/fields.py +++ b/baph/forms/fields.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from importlib import import_module import json @@ -7,6 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from baph.utils.collections import duck_type_collection +import six def coerce_to_list(value): @@ -19,7 +21,7 @@ def coerce_to_list(value): return list(value) if isinstance(value, dict): # this has no ordering, so will probably break things - return value.items() + return list(value.items()) if isinstance(value, set): # this has no ordering, so will probably break things return list(value) @@ -29,7 +31,7 @@ class NullCharField(forms.CharField): " CharField that does not cast None to '' " def to_python(self, value): "Returns a Unicode object." - if isinstance(value, basestring): + if isinstance(value, six.string_types): value = value.strip() if value in validators.EMPTY_VALUES: return None @@ -66,7 +68,7 @@ def validate_collection(self, data, collection_class=None): raise forms.ValidationError( _('Expected %s, got %s') % (expected_class, found_class)) - values = data.itervalues() if isinstance(data, dict) else iter(data) + values = six.itervalues(data) if isinstance(data, dict) else iter(data) for v in values: self.validate_collection(v, collection_class) @@ -99,16 +101,16 @@ class JsonField(forms.CharField): def __init__(self, *args, **kwargs): content_length_func = kwargs.pop('content_length_func', None) super(JsonField, self).__init__(*args, **kwargs) - if isinstance(content_length_func, basestring): + if isinstance(content_length_func, six.string_types): module, func_name = content_length_func.rsplit('.', 1) module = import_module(module) content_length_func = getattr(module, func_name) self.content_length_func = content_length_func def _as_string(self, value): - if isinstance(value, basestring): + if isinstance(value, six.string_types): return value - return unicode(value) + return six.text_type(value) def _get_content_length(self, value): """ @@ -127,7 +129,7 @@ def to_python(self, value): raise forms.ValidationError(_('Max length for this field is ' '%s bytes') % self.max_length) - if isinstance(value, basestring): + if isinstance(value, six.string_types): try: value = json.loads(value) except: @@ -144,7 +146,7 @@ def _clean_value(self, value): """ Clean a single value in a list """ - if self.strip and isinstance(value, basestring): + if self.strip and isinstance(value, six.string_types): return value.strip() return value diff --git a/baph/forms/forms.py b/baph/forms/forms.py index 8c3e4fb..84b0280 100644 --- a/baph/forms/forms.py +++ b/baph/forms/forms.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django import forms from django.core.exceptions import ImproperlyConfigured from django.utils.datastructures import SortedDict @@ -14,6 +15,8 @@ from baph.auth.models import Organization from baph.db import types, ORM from baph.forms import fields +from six.moves import map +import six FIELD_MAP = { @@ -77,17 +80,17 @@ def model_to_dict(instance, fields=None, exclude=None): data = {} unloaded_attrs = inspect(instance).unloaded for f in opts.fields: - if f.name in unloaded_attrs: - if issubclass(f.data_type, orm.Base): - # skip relations that haven't been loaded yet - continue - if not getattr(f, 'editable', False): - continue - if fields and not f.name in fields: - continue - if exclude and f.name in exclude: - continue - data[f.name] = getattr(instance, f.name) + if f.name in unloaded_attrs: + if issubclass(f.data_type, orm.Base): + # skip relations that haven't been loaded yet + continue + if not getattr(f, 'editable', False): + continue + if fields and not f.name in fields: + continue + if exclude and f.name in exclude: + continue + data[f.name] = getattr(instance, f.name) return data def fields_for_model(model, fields=None, exclude=None, widgets=None, @@ -109,13 +112,13 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None, continue if issubclass(f.data_type, Base): - # TODO: Auto-generate fields, control via 'fields' param - if fields is not None and f.name in fields: - # manually included field - pass - else: - # skip relations unless manually requested - continue + # TODO: Auto-generate fields, control via 'fields' param + if fields is not None and f.name in fields: + # manually included field + pass + else: + # skip relations unless manually requested + continue kwargs = {} if widgets and f.name in widgets: @@ -200,6 +203,7 @@ def __new__(cls, name, bases, attrs): except NameError: parents = None declared_fields = forms.forms.get_declared_fields(bases, attrs, False) + new_class = super(SQLAModelFormMetaclass, cls) \ .__new__(cls, name, bases, attrs) if not parents: @@ -207,6 +211,7 @@ def __new__(cls, name, bases, attrs): if 'media' not in attrs: new_class.media = forms.widgets.media_property(new_class) + opts = new_class._meta = SQLAModelFormOptions(getattr(new_class, 'Meta', None)) if opts.model: # If a model is defined, extract form fields from it. @@ -227,30 +232,31 @@ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, opts = self._meta exclude = list(opts.exclude) if opts.model is None: - raise ValueError('ModelForm has no model class specified.') + raise ValueError('ModelForm has no model class specified.') self.nested = nested if self.nested: - exclude.extend(opts.exclude_on_nested) + exclude.extend(opts.exclude_on_nested) if instance is None: - exclude.extend(opts.exclude_on_create) - self.instance = opts.model() - object_data = {} + exclude.extend(opts.exclude_on_create) + self.instance = opts.model() + object_data = {} else: - self.instance = instance - object_data = model_to_dict(instance, opts.fields, exclude) - if has_identity(instance): - exclude.extend(opts.exclude_on_update) - else: - exclude.extend(opts.exclude_on_create) + self.instance = instance + object_data = model_to_dict(instance, opts.fields, exclude) + if has_identity(instance): + exclude.extend(opts.exclude_on_update) + else: + exclude.extend(opts.exclude_on_create) if initial is not None: - object_data.update(initial) + object_data.update(initial) object_data.update(data) + super(BaseSQLAModelForm, self).__init__(object_data, files, auto_id, prefix) for k in exclude: - if k in self.fields: - del self.fields[k] + if k in self.fields: + del self.fields[k] def save(self, commit=False): """ @@ -267,9 +273,7 @@ def save(self, commit=False): return save_instance(self, self.instance, self._meta.fields, fail_message, commit, self._meta.exclude) -class SQLAModelForm(BaseSQLAModelForm): - __metaclass__ = SQLAModelFormMetaclass - +class SQLAModelForm(six.with_metaclass(SQLAModelFormMetaclass, BaseSQLAModelForm)): def clean_unique_field(self, key, **kwargs): orm = ORM.get() value = self.cleaned_data[key] @@ -287,7 +291,7 @@ def clean_unique_field(self, key, **kwargs): # if all filter keys exist on the base mapper, query the base class # if the base class is missing any properties, query the # polymorphic subclass explicitly - if all(map(mapper.has_property, filters.keys())): + if all(map(mapper.has_property, list(filters.keys()))): model = mapper.class_ session = orm.sessionmaker() diff --git a/baph/forms/models.py b/baph/forms/models.py index f30017f..67e75b0 100644 --- a/baph/forms/models.py +++ b/baph/forms/models.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import warnings from baph.db import types @@ -12,6 +13,7 @@ from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty from sqlalchemy.sql.expression import _BinaryExpression, _Label +import six FIELD_MAP = { @@ -228,5 +230,5 @@ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, object_data, error_class, label_suffix, empty_permitted) -class ModelForm(BaseModelForm): - __metaclass__ = ModelFormMetaclass +class ModelForm(six.with_metaclass(ModelFormMetaclass, BaseModelForm)): + pass diff --git a/baph/forms/widgets.py b/baph/forms/widgets.py index 067b999..194ba92 100644 --- a/baph/forms/widgets.py +++ b/baph/forms/widgets.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.forms.widgets import TextInput, DateInput, DateTimeInput, TimeInput class HTML5EmailInput(TextInput): diff --git a/baph/localflavor/generic/__init__.py b/baph/localflavor/generic/__init__.py index 1335793..bc57c26 100644 --- a/baph/localflavor/generic/__init__.py +++ b/baph/localflavor/generic/__init__.py @@ -9,6 +9,7 @@ Attachment: country_and_language_fields_trunk.4.patch ''' +from __future__ import absolute_import from django.conf import settings from django.core.exceptions import ValidationError from django.utils.translation import ugettext as _ diff --git a/baph/localflavor/generic/data/ar/subdivisions.py b/baph/localflavor/generic/data/ar/subdivisions.py index 720c91e..972f492 100644 --- a/baph/localflavor/generic/data/ar/subdivisions.py +++ b/baph/localflavor/generic/data/ar/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/at/subdivisions.py b/baph/localflavor/generic/data/at/subdivisions.py index a9502c8..0644eb1 100644 --- a/baph/localflavor/generic/data/at/subdivisions.py +++ b/baph/localflavor/generic/data/at/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/au/subdivisions.py b/baph/localflavor/generic/data/au/subdivisions.py index 172a390..5d41ef7 100644 --- a/baph/localflavor/generic/data/au/subdivisions.py +++ b/baph/localflavor/generic/data/au/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/be/subdivisions.py b/baph/localflavor/generic/data/be/subdivisions.py index d861184..2f1909a 100644 --- a/baph/localflavor/generic/data/be/subdivisions.py +++ b/baph/localflavor/generic/data/be/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/bo/subdivisions.py b/baph/localflavor/generic/data/bo/subdivisions.py index 3be16e2..bf6ac3a 100644 --- a/baph/localflavor/generic/data/bo/subdivisions.py +++ b/baph/localflavor/generic/data/bo/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/br/subdivisions.py b/baph/localflavor/generic/data/br/subdivisions.py index 58e48da..642baba 100644 --- a/baph/localflavor/generic/data/br/subdivisions.py +++ b/baph/localflavor/generic/data/br/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/ca/subdivisions.py b/baph/localflavor/generic/data/ca/subdivisions.py index cd88613..e1f547d 100644 --- a/baph/localflavor/generic/data/ca/subdivisions.py +++ b/baph/localflavor/generic/data/ca/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/ch/subdivisions.py b/baph/localflavor/generic/data/ch/subdivisions.py index 19e52d5..fbf8404 100644 --- a/baph/localflavor/generic/data/ch/subdivisions.py +++ b/baph/localflavor/generic/data/ch/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/cl/subdivisions.py b/baph/localflavor/generic/data/cl/subdivisions.py index ec39905..cd2dfe5 100644 --- a/baph/localflavor/generic/data/cl/subdivisions.py +++ b/baph/localflavor/generic/data/cl/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/co/subdivisions.py b/baph/localflavor/generic/data/co/subdivisions.py index 6d6696d..b544711 100644 --- a/baph/localflavor/generic/data/co/subdivisions.py +++ b/baph/localflavor/generic/data/co/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/cr/subdivisions.py b/baph/localflavor/generic/data/cr/subdivisions.py index 02ddaa3..a258953 100644 --- a/baph/localflavor/generic/data/cr/subdivisions.py +++ b/baph/localflavor/generic/data/cr/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/do/subdivisions.py b/baph/localflavor/generic/data/do/subdivisions.py index 7cdd6f3..c66910f 100644 --- a/baph/localflavor/generic/data/do/subdivisions.py +++ b/baph/localflavor/generic/data/do/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/ec/subdivisions.py b/baph/localflavor/generic/data/ec/subdivisions.py index 3ed624a..ff43729 100644 --- a/baph/localflavor/generic/data/ec/subdivisions.py +++ b/baph/localflavor/generic/data/ec/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/es/subdivisions.py b/baph/localflavor/generic/data/es/subdivisions.py index 98fe0ae..7181c6d 100644 --- a/baph/localflavor/generic/data/es/subdivisions.py +++ b/baph/localflavor/generic/data/es/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/gb/subdivisions.py b/baph/localflavor/generic/data/gb/subdivisions.py index 758e98d..5a956db 100644 --- a/baph/localflavor/generic/data/gb/subdivisions.py +++ b/baph/localflavor/generic/data/gb/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/gt/subdivisions.py b/baph/localflavor/generic/data/gt/subdivisions.py index 02ba412..c96701a 100644 --- a/baph/localflavor/generic/data/gt/subdivisions.py +++ b/baph/localflavor/generic/data/gt/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/id_/subdivisions.py b/baph/localflavor/generic/data/id_/subdivisions.py index 8f08966..6e4706b 100644 --- a/baph/localflavor/generic/data/id_/subdivisions.py +++ b/baph/localflavor/generic/data/id_/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/it/subdivisions.py b/baph/localflavor/generic/data/it/subdivisions.py index 3bb4d4b..bd05c2e 100644 --- a/baph/localflavor/generic/data/it/subdivisions.py +++ b/baph/localflavor/generic/data/it/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/kr/subdivisions.py b/baph/localflavor/generic/data/kr/subdivisions.py index 6a73d02..f025f81 100644 --- a/baph/localflavor/generic/data/kr/subdivisions.py +++ b/baph/localflavor/generic/data/kr/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/mx/subdivisions.py b/baph/localflavor/generic/data/mx/subdivisions.py index c6987b8..4fc14d5 100644 --- a/baph/localflavor/generic/data/mx/subdivisions.py +++ b/baph/localflavor/generic/data/mx/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/ng/subdivisions.py b/baph/localflavor/generic/data/ng/subdivisions.py index ef9641c..2d0f28b 100644 --- a/baph/localflavor/generic/data/ng/subdivisions.py +++ b/baph/localflavor/generic/data/ng/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/ni/subdivisions.py b/baph/localflavor/generic/data/ni/subdivisions.py index 2dd912d..d77a8ca 100644 --- a/baph/localflavor/generic/data/ni/subdivisions.py +++ b/baph/localflavor/generic/data/ni/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/pa/subdivisions.py b/baph/localflavor/generic/data/pa/subdivisions.py index 646173c..892ec66 100644 --- a/baph/localflavor/generic/data/pa/subdivisions.py +++ b/baph/localflavor/generic/data/pa/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/pe/subdivisions.py b/baph/localflavor/generic/data/pe/subdivisions.py index b7bcfc5..838ec58 100644 --- a/baph/localflavor/generic/data/pe/subdivisions.py +++ b/baph/localflavor/generic/data/pe/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/py/subdivisions.py b/baph/localflavor/generic/data/py/subdivisions.py index fbd6d2a..103d3ba 100644 --- a/baph/localflavor/generic/data/py/subdivisions.py +++ b/baph/localflavor/generic/data/py/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/ru/subdivisions.py b/baph/localflavor/generic/data/ru/subdivisions.py index c852477..c8a3c72 100644 --- a/baph/localflavor/generic/data/ru/subdivisions.py +++ b/baph/localflavor/generic/data/ru/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/sv/subdivisions.py b/baph/localflavor/generic/data/sv/subdivisions.py index f536151..f98d077 100644 --- a/baph/localflavor/generic/data/sv/subdivisions.py +++ b/baph/localflavor/generic/data/sv/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/us/subdivisions.py b/baph/localflavor/generic/data/us/subdivisions.py index 1b7e0cd..0bc521a 100644 --- a/baph/localflavor/generic/data/us/subdivisions.py +++ b/baph/localflavor/generic/data/us/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/data/uy/subdivisions.py b/baph/localflavor/generic/data/uy/subdivisions.py index 62dcb0c..3f62fa8 100644 --- a/baph/localflavor/generic/data/uy/subdivisions.py +++ b/baph/localflavor/generic/data/uy/subdivisions.py @@ -1,6 +1,7 @@ # encoding: utf8 from __future__ import unicode_literals +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/baph/localflavor/generic/forms.py b/baph/localflavor/generic/forms.py index 9e1696c..3d631e0 100644 --- a/baph/localflavor/generic/forms.py +++ b/baph/localflavor/generic/forms.py @@ -13,6 +13,7 @@ Attachment: country_and_language_fields_trunk.4.patch ''' from __future__ import unicode_literals +from __future__ import absolute_import from itertools import chain from django import forms diff --git a/baph/localflavor/tests/forms.py b/baph/localflavor/tests/forms.py index f714b82..55e8a24 100644 --- a/baph/localflavor/tests/forms.py +++ b/baph/localflavor/tests/forms.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest from django import forms diff --git a/baph/middleware/debug.py b/baph/middleware/debug.py index e216e49..30b0eba 100644 --- a/baph/middleware/debug.py +++ b/baph/middleware/debug.py @@ -7,6 +7,7 @@ .. moduleauthor:: Mark Lee ''' +from __future__ import absolute_import from coffin.common import env from django.conf import settings from django.http import HttpResponse, HttpResponseServerError diff --git a/baph/middleware/orm.py b/baph/middleware/orm.py index d6b35bd..9f85306 100755 --- a/baph/middleware/orm.py +++ b/baph/middleware/orm.py @@ -6,6 +6,7 @@ .. moduleauthor:: Mark Lee ''' +from __future__ import absolute_import from baph.db.orm import ORM diff --git a/baph/middleware/ssl.py b/baph/middleware/ssl.py index 595ce72..55b42d8 100644 --- a/baph/middleware/ssl.py +++ b/baph/middleware/ssl.py @@ -11,6 +11,7 @@ Foundation License, version 2 `_. ''' +from __future__ import absolute_import from django.conf import settings from django.http import HttpResponseRedirect diff --git a/baph/template/shortcuts.py b/baph/template/shortcuts.py index 12aa9f9..dd1c2ff 100644 --- a/baph/template/shortcuts.py +++ b/baph/template/shortcuts.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.utils.importing import import_attr +import six base_render_to_response = import_attr(['coffin.shortcuts'], ['render_to_response']) RequestContext = import_attr(['coffin.template'], 'RequestContext') @@ -34,7 +36,7 @@ def render_to_string(template_or_template_name, dictionary=None, request=None): request_context = RequestContext(request) if request else None if isinstance(template_or_template_name, (list, tuple)): template = select_template(template_or_template_name) - elif isinstance(template_or_template_name, basestring): + elif isinstance(template_or_template_name, six.string_types): template = get_template(template_or_template_name) else: # assume it's a template diff --git a/baph/test/__init__.py b/baph/test/__init__.py index f00f841..1959a8a 100644 --- a/baph/test/__init__.py +++ b/baph/test/__init__.py @@ -1 +1,2 @@ +from __future__ import absolute_import from baph.test.testcases import TestCase diff --git a/baph/test/cloning.py b/baph/test/cloning.py index 743e3f4..e357780 100644 --- a/baph/test/cloning.py +++ b/baph/test/cloning.py @@ -1,13 +1,15 @@ +from __future__ import absolute_import import copy import inspect as pyinspect from sqlalchemy import inspect from sqlalchemy.ext.associationproxy import ASSOCIATION_PROXY from sqlalchemy.ext.orderinglist import OrderingList -from sqlalchemy.orm.util import identity_key from baph.db.models.cloning import * +from baph.db.models.utils import identity_key from baph.utils.collections import duck_type_collection +from six.moves import zip def is_polymorphic(cls): @@ -284,7 +286,7 @@ def normalize_collections(self, old, new): elif collection_class == dict: # we want to compare objects with matching keys, so we order # the objects by key - self.assertItemsEqual(old.keys(), new.keys(), + self.assertItemsEqual(list(old.keys()), list(new.keys()), 'mapped collections have different keys') old = [i[1] for i in sorted(old.items())] new = [i[1] for i in sorted(new.items())] diff --git a/baph/test/mixins/query_logging.py b/baph/test/mixins/query_logging.py index d107d79..92ba27b 100644 --- a/baph/test/mixins/query_logging.py +++ b/baph/test/mixins/query_logging.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from importlib import import_module import inspect @@ -116,7 +118,7 @@ def callback(self, conn, cursor, stmt, params, context, executemany): info = self.process_stack() self.queries.append((stmt, params, info)) if self.emit: - print '\n[QUERY]:', self.queries[-1] + print('\n[QUERY]:', self.queries[-1]) @property def count(self): diff --git a/baph/test/signals.py b/baph/test/signals.py index bc95034..f8d3656 100644 --- a/baph/test/signals.py +++ b/baph/test/signals.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.dispatch import Signal diff --git a/baph/test/simple.py b/baph/test/simple.py index b20664a..1e72bdb 100644 --- a/baph/test/simple.py +++ b/baph/test/simple.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from copy import deepcopy import sys import unittest as real_unittest @@ -230,7 +232,7 @@ def setup_databases(self, **kwargs): conflicts = schemas.intersection(existing_schemas) if conflicts: for c in conflicts: - print 'drop schema %s;' % c + print('drop schema %s;' % c) sys.exit('The following schemas are already present: %s. ' \ 'TestRunner cannot proceeed' % ','.join(conflicts)) diff --git a/baph/test/testcases.py b/baph/test/testcases.py index e2bedad..7a29f77 100644 --- a/baph/test/testcases.py +++ b/baph/test/testcases.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from collections import defaultdict import json import time @@ -208,8 +210,8 @@ def run(self, *args, **kwargs): @classmethod def print_timings(cls): total = cls.test_end_time - cls.test_start_time - print '\n%s timings:' % cls.__name__ - print ' %d test(s) run, totalling %.03fs' % (cls.tests_run, total) + print('\n%s timings:' % cls.__name__) + print(' %d test(s) run, totalling %.03fs' % (cls.tests_run, total)) if not cls.timings: return items = sorted(cls.timings.items()) @@ -222,8 +224,8 @@ def print_timings(cls): keys[i] = ' %s' % end max_key_len = max(len(k) for k in keys) for i, (k, v) in enumerate(items): - print ' %s: %d calls, totalling %.03fs (%.02f%%)' % ( - keys[i].ljust(max_key_len), len(v), sum(v), 100.0*sum(v)/total) + print(' %s: %d calls, totalling %.03fs (%.02f%%)' % ( + keys[i].ljust(max_key_len), len(v), sum(v), 100.0*sum(v)/total)) @classmethod def load_fixtures(cls, *fixtures): @@ -376,13 +378,13 @@ def assertCacheKeyUnchanged(self, key, version=None, cache_alias=None): def assertCacheKeyCreated(self, key, version=None, cache_alias=None): cache = get_cache(cache_alias) if cache_alias else self.cache raw_key = cache.make_key(key, version=version) - self.assertNotIn(raw_key, self._initial(cache_alias).keys()) + self.assertNotIn(raw_key, list(self._initial(cache_alias).keys())) self.assertIn(raw_key, cache.get_all_keys()) def assertCacheKeyNotCreated(self, key, version=None, cache_alias=None): cache = get_cache(cache_alias) if cache_alias else self.cache raw_key = cache.make_key(key, version=version) - self.assertNotIn(raw_key, self._initial(cache_alias).keys()) + self.assertNotIn(raw_key, list(self._initial(cache_alias).keys())) self.assertNotIn(raw_key, cache.get_all_keys()) def assertCacheKeyIncremented(self, key, version=None, cache_alias=None): @@ -403,28 +405,28 @@ def assertCacheKeyInvalidated(self, key, version=None, cache_alias=None): cache = get_cache(cache_alias) if cache_alias else self.cache raw_key = cache.make_key(key, version=version) current_value = cache.get(key, version=version) - self.assertIn(raw_key, self._initial(cache_alias).keys()) + self.assertIn(raw_key, list(self._initial(cache_alias).keys())) self.assertEqual(current_value, None) def assertCacheKeyNotInvalidated(self, key, version=None, cache_alias=None): cache = get_cache(cache_alias) if cache_alias else self.cache raw_key = cache.make_key(key, version=version) current_value = cache.get(key, version=version) - self.assertIn(raw_key, self._initial(cache_alias).keys()) + self.assertIn(raw_key, list(self._initial(cache_alias).keys())) self.assertNotEqual(current_value, None) def assertPointerKeyInvalidated(self, key, version=None, cache_alias=None): cache = get_cache(cache_alias) if cache_alias else self.cache raw_key = cache.make_key(key, version=version) current_value = cache.get(key, version=version) - self.assertIn(raw_key, self._initial(cache_alias).keys()) + self.assertIn(raw_key, list(self._initial(cache_alias).keys())) self.assertEqual(current_value, 0) def assertPointerKeyNotInvalidated(self, key, version=None, cache_alias=None): cache = get_cache(cache_alias) if cache_alias else self.cache raw_key = cache.make_key(key, version=version) current_value = cache.get(key, version=version) - self.assertIn(raw_key, self._initial(cache_alias).keys()) + self.assertIn(raw_key, list(self._initial(cache_alias).keys())) self.assertNotEqual(current_value, 0) @@ -440,6 +442,7 @@ class MemcacheTestCase(MemcacheMixin, TestCase): def _fixture_setup(self): super(MemcacheTestCase, self)._fixture_setup() self.cache.flush_all() + time.sleep(1) # to prevent new cache operations from interrupting flush def setUp(self, objs={}, counts={}): self.initial = {} @@ -449,6 +452,7 @@ class MemcacheLSTestCase(MemcacheMixin, LiveServerTestCase): def _fixture_setup(self): super(MemcacheLSTestCase, self)._fixture_setup() self.cache.flush_all() + time.sleep(1) # to prevent new cache operations from interrupting flush def setUp(self, objs={}, counts={}): self.initial = {} diff --git a/baph/utils/assets/__init__.py b/baph/utils/assets/__init__.py index 8a3ea10..072ccce 100644 --- a/baph/utils/assets/__init__.py +++ b/baph/utils/assets/__init__.py @@ -54,6 +54,7 @@ --------- ''' +from __future__ import absolute_import from ..importing import import_attr import gzip import os diff --git a/baph/utils/assets/css.py b/baph/utils/assets/css.py index cee6041..7259554 100644 --- a/baph/utils/assets/css.py +++ b/baph/utils/assets/css.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from cssutils import parseString, replaceUrls, resolveImports, ser from django.conf import settings import os import re -from urllib import pathname2url -from urlparse import urlsplit +from six.moves.urllib.request import pathname2url +from six.moves.urllib.parse import urlsplit def get_recursive_imports(sheet, base=None): diff --git a/baph/utils/assets/jinja2.py b/baph/utils/assets/jinja2.py index bab768b..2561bef 100644 --- a/baph/utils/assets/jinja2.py +++ b/baph/utils/assets/jinja2.py @@ -27,7 +27,7 @@ class AssetExtension(Extension): def parse(self, parser): stream = parser.stream - tag = stream.next() + tag = next(stream) if stream.current.test('string'): path = parser.parse_primary() else: @@ -35,7 +35,7 @@ def parse(self, parser): "%s" requires path to asset file, relative to STATICFILES_URL''' % tag.value, tag.lineno) while not parser.stream.current.type == 'block_end': - parser.stream.next() + next(parser.stream) result = self.call_method(self.build_method, args=[path]) return nodes.Output([nodes.MarkSafe(result)]).set_lineno(tag.lineno) diff --git a/baph/utils/assets/js.py b/baph/utils/assets/js.py index 081291f..b1f0c64 100644 --- a/baph/utils/assets/js.py +++ b/baph/utils/assets/js.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from subprocess import PIPE, Popen diff --git a/baph/utils/assets/management/commands/deploy_static.py b/baph/utils/assets/management/commands/deploy_static.py index 4c4ca21..ef18259 100644 --- a/baph/utils/assets/management/commands/deploy_static.py +++ b/baph/utils/assets/management/commands/deploy_static.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from django.conf import settings from django.core.files import File from gzip import GzipFile diff --git a/baph/utils/collections.py b/baph/utils/collections.py index 3979e67..b4e9e3c 100644 --- a/baph/utils/collections.py +++ b/baph/utils/collections.py @@ -16,6 +16,7 @@ from collections import defaultdict, OrderedDict +from six import PY2 from sqlalchemy.ext.associationproxy import _AssociationDict from sqlalchemy.util import duck_type_collection as sqla_duck_type_collection @@ -49,10 +50,13 @@ def flatten(l): return ltype(l) -class OrderedDefaultDict(defaultdict, OrderedDict): - '''A :class:`dict` subclass with the characteristics of both - :class:`~collections.defaultdict` and :class:`~collections.OrderedDict`. - ''' - def __init__(self, default_factory, *args, **kwargs): - defaultdict.__init__(self, default_factory) - OrderedDict.__init__(self, *args, **kwargs) +if PY2: + class OrderedDefaultDict(defaultdict, OrderedDict): + '''A :class:`dict` subclass with the characteristics of both + :class:`~collections.defaultdict` and :class:`~collections.OrderedDict`. + ''' + def __init__(self, default_factory, *args, **kwargs): + defaultdict.__init__(self, default_factory) + OrderedDict.__init__(self, *args, **kwargs) +else: + OrderedDefaultDict = defaultdict diff --git a/baph/utils/encoding.py b/baph/utils/encoding.py index 125418f..33d6194 100644 --- a/baph/utils/encoding.py +++ b/baph/utils/encoding.py @@ -1,9 +1,22 @@ # backport from django 1.6 +from __future__ import absolute_import from __future__ import unicode_literals - -import htmlentitydefs import re +import six.moves.html_entities +from six import unichr + +if six.PY3: + from django.utils.encoding import force_bytes + from django.utils.encoding import smart_bytes + from django.utils.encoding import force_str as force_unicode + from django.utils.encoding import smart_str as smart_unicode +else: + from django.utils.encoding import force_str as force_bytes + from django.utils.encoding import smart_str as smart_bytes + from django.utils.encoding import force_unicode + from django.utils.encoding import smart_unicode + def unescape(text): """Removes HTML or XML character references @@ -27,7 +40,7 @@ def fixup(m): else: # named entity try: - text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]) + text = unichr(six.moves.html_entities.name2codepoint[text[1:-1]]) except KeyError: pass return text # leave as is diff --git a/baph/utils/functional.py b/baph/utils/functional.py index c8bc18f..3e17071 100644 --- a/baph/utils/functional.py +++ b/baph/utils/functional.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import functools @@ -13,7 +14,7 @@ def __get__(self, instance, type=None): def __call__(self, *args, **kwargs): instance = args[0] - key = (self.func, type(instance), args[1:], frozenset(kwargs.items())) + key = (self.func, type(instance), args[1:], frozenset(list(kwargs.items()))) try: res = self.cache[key] except KeyError: diff --git a/baph/utils/glob.py b/baph/utils/glob.py index 321e7b9..0992d1d 100644 --- a/baph/utils/glob.py +++ b/baph/utils/glob.py @@ -1,9 +1,9 @@ +from __future__ import absolute_import from __future__ import unicode_literals - import os.path import re -from django.utils import six +import six # backport of Python 3.4's glob.escape @@ -18,4 +18,4 @@ def glob_escape(pathname): """ drive, pathname = os.path.splitdrive(pathname) pathname = _magic_check.sub(r'[\1]', pathname) - return drive + pathname \ No newline at end of file + return drive + pathname diff --git a/baph/utils/log.py b/baph/utils/log.py index aab8e52..a21d218 100644 --- a/baph/utils/log.py +++ b/baph/utils/log.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import logging from django.utils.log import DEFAULT_LOGGING diff --git a/baph/utils/module_loading.py b/baph/utils/module_loading.py index 960df1b..06ecc05 100644 --- a/baph/utils/module_loading.py +++ b/baph/utils/module_loading.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import sys from importlib import import_module diff --git a/baph/utils/path.py b/baph/utils/path.py index 195e89c..d7368cd 100644 --- a/baph/utils/path.py +++ b/baph/utils/path.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.utils.importing import import_attr import os diff --git a/baph/utils/s3.py b/baph/utils/s3.py index 828d09c..ffd547b 100644 --- a/baph/utils/s3.py +++ b/baph/utils/s3.py @@ -28,11 +28,13 @@ ------- ''' +from __future__ import absolute_import from boto.s3.connection import S3Connection from boto.s3.key import Key from cStringIO import StringIO from django.conf import settings from PIL import Image +import six # Amazon S3 connection connection = S3Connection(settings.AWS_ACCESS_KEY_ID, @@ -54,7 +56,7 @@ def __contains__(self, key): return self.bucket.get_key(key) is not None def __getitem__(self, key): - if not isinstance(key, basestring): + if not isinstance(key, six.string_types): raise TypeError('key is not a string') item = self.bucket.get_key(key) if not item: @@ -66,7 +68,7 @@ def __getitem__(self, key): item.close() def __delitem__(self, key): - if not isinstance(key, basestring): + if not isinstance(key, six.string_types): raise TypeError('key is not a string') item = self.bucket.get_key(key) if not item: @@ -144,7 +146,7 @@ def upload(self, image, basename): if self.img_type is None: img = Image.open(image) format = img.format.lower() - types = [k for k, v in self.__pil_types.iteritems() if v == format] + types = [k for k, v in six.iteritems(self.__pil_types) if v == format] if len(types) > 0: img_type = types[0] else: diff --git a/baph/utils/strings.py b/baph/utils/strings.py index 8094a96..8881bf5 100644 --- a/baph/utils/strings.py +++ b/baph/utils/strings.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import import random import string import time +from six.moves import range def random_string(size=16, chars=None): diff --git a/baph/utils/testing.py b/baph/utils/testing.py index a0b3b43..ac9d148 100644 --- a/baph/utils/testing.py +++ b/baph/utils/testing.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import inspect import unittest diff --git a/baph/utils/text.py b/baph/utils/text.py index ec2dbbe..29b899d 100644 --- a/baph/utils/text.py +++ b/baph/utils/text.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import re diff --git a/docs/_ext/djangodocs.py b/docs/_ext/djangodocs.py index f35f780..144d464 100644 --- a/docs/_ext/djangodocs.py +++ b/docs/_ext/djangodocs.py @@ -1,5 +1,6 @@ """Sphinx plugins for Django documentation.""" +from __future__ import absolute_import from baph.utils.importing import import_any_module from django.utils.importlib import import_module json = import_any_module(['json', 'simplejson', 'django.utils.simplejson']) @@ -222,7 +223,7 @@ def finish(self): return self.info(bold("writing templatebuiltins.js...")) try: - xrefs = self.env.reftargets.keys() + xrefs = list(self.env.reftargets.keys()) templatebuiltins = dict([('ttags', [n for (t, n) in xrefs if t == 'ttag']), ('tfilters', [n for (t, n) in xrefs diff --git a/docs/conf.py b/docs/conf.py index ed9febf..3b6336f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,6 +12,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. +from __future__ import absolute_import import os import sys diff --git a/runtests.py b/runtests.py index 3cd97a5..2357c79 100755 --- a/runtests.py +++ b/runtests.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import absolute_import import os import sys from unittest2 import main diff --git a/setup.py b/setup.py index 4085a76..8e72ce0 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import absolute_import from distutils.core import setup from setuptools import find_packages @@ -12,7 +13,7 @@ 'funcy', 'SQLAlchemy >= 0.9.0', 'python-dotenv == 0.7.1', - 'functools32 == 3.2.3.post2', + 'functools32 == 3.2.3.post2; python_version < "3.0"', 'chainmap == 1.0.2', ], include_package_data=True, diff --git a/tests/auth/registration/test_forms.py b/tests/auth/registration/test_forms.py index 15f6ea6..989a472 100644 --- a/tests/auth/registration/test_forms.py +++ b/tests/auth/registration/test_forms.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import User from baph.auth.registration import forms from baph.db.orm import ORM diff --git a/tests/auth/registration/test_models.py b/tests/auth/registration/test_models.py index 49f0bba..4646cea 100644 --- a/tests/auth/registration/test_models.py +++ b/tests/auth/registration/test_models.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import User from baph.auth.registration.models import RegistrationProfile from baph.db.orm import ORM @@ -9,6 +10,7 @@ from django.conf import settings from django.core import mail, management from django.utils.hashcompat import sha_constructor +import six class RegistrationModelTests(BaseTestCase): @@ -72,7 +74,7 @@ def test_profile_creation(self): self.assertEqual(ct, 1) self.assertEqual(profile.user.id, new_user.id) self.assertRegexpMatches(profile.activation_key, '^[a-f0-9]{40}$') - self.assertEqual(unicode(profile), + self.assertEqual(six.text_type(profile), u'Registration information for alice') def test_activation_email(self): diff --git a/tests/auth/registration/test_views.py b/tests/auth/registration/test_views.py index a3b94f5..40736c3 100644 --- a/tests/auth/registration/test_views.py +++ b/tests/auth/registration/test_views.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from baph.auth.models import User from baph.auth.registration import forms from baph.auth.registration.models import RegistrationProfile diff --git a/tests/auth/registration/urls.py b/tests/auth/registration/urls.py index 99cdb12..c8fe14f 100644 --- a/tests/auth/registration/urls.py +++ b/tests/auth/registration/urls.py @@ -10,6 +10,7 @@ """ +from __future__ import absolute_import from baph.auth.registration.views import activate, register from coffin.views.generic.simple import direct_to_template from django.conf.urls.defaults import include, patterns, url diff --git a/tests/auth/test_models.py b/tests/auth/test_models.py index b8b2df5..01d5ab9 100644 --- a/tests/auth/test_models.py +++ b/tests/auth/test_models.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import AnonymousUser, orm, User from baph.test.base import BaseTestCase from django.conf import settings from django.core import mail +import six class AuthTestCase(BaseTestCase): @@ -52,7 +54,7 @@ def test_create_user(self): self.assertTrue(u.is_authenticated()) self.assertFalse(u.is_staff) self.assertFalse(u.is_superuser) - self.assertEqual(unicode(u), u'testuser') + self.assertEqual(six.text_type(u), u'testuser') self.assertEqual(u.get_full_name(), u'¡ π') u2 = User.create_user(u'testuser2', 'test2@example.com', diff --git a/tests/auth/test_profile.py b/tests/auth/test_profile.py index c1614dd..6482607 100644 --- a/tests/auth/test_profile.py +++ b/tests/auth/test_profile.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import orm, SiteProfileNotAvailable, User from baph.test.base import TestCase from django.conf import settings diff --git a/tests/auth/test_views.py b/tests/auth/test_views.py index 6e9c2b4..461024f 100644 --- a/tests/auth/test_views.py +++ b/tests/auth/test_views.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import orm, User from baph.test.base import BaseTestCase from django.conf import settings diff --git a/tests/decorators/test_db.py b/tests/decorators/test_db.py index d83d8c7..b26a562 100644 --- a/tests/decorators/test_db.py +++ b/tests/decorators/test_db.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.orm import ORM from baph.decorators.db import sqlalchemy_session from baph.test.base import TestCase diff --git a/tests/decorators/test_json.py b/tests/decorators/test_json.py index 8e2cd43..dafc498 100644 --- a/tests/decorators/test_json.py +++ b/tests/decorators/test_json.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.test.base import BaseTestCase from baph.decorators.json import json diff --git a/tests/decorators/urls.py b/tests/decorators/urls.py index 5c8e283..36bf50a 100644 --- a/tests/decorators/urls.py +++ b/tests/decorators/urls.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from django.conf.urls.defaults import patterns urlpatterns = patterns('tests.decorators.views', diff --git a/tests/decorators/views.py b/tests/decorators/views.py index 7deb3ae..0d7cd66 100644 --- a/tests/decorators/views.py +++ b/tests/decorators/views.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.decorators.json import JSONify, render_to_json from django.http import HttpResponse, HttpResponseRedirect diff --git a/tests/localflavor/test_generic.py b/tests/localflavor/test_generic.py index 8edfe77..8ab958b 100644 --- a/tests/localflavor/test_generic.py +++ b/tests/localflavor/test_generic.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.localflavor.generic import COUNTRIES from baph.localflavor.generic.forms import ( CountryField, LanguageField, StateProvinceField, StateProvinceSelect, diff --git a/tests/piston/test_models.py b/tests/piston/test_models.py index 5f41d6a..460b35e 100644 --- a/tests/piston/test_models.py +++ b/tests/piston/test_models.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import orm, User from baph.piston.models import Consumer from baph.test.base import BaseTestCase diff --git a/tests/piston/test_oauth.py b/tests/piston/test_oauth.py index 5d63ac4..eddf99a 100644 --- a/tests/piston/test_oauth.py +++ b/tests/piston/test_oauth.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.auth.models import orm, User from baph.piston.models import Consumer from baph.test.oauth import OAuthTestCase diff --git a/tests/project/api/handlers.py b/tests/project/api/handlers.py index f302f91..3e2ad5b 100644 --- a/tests/project/api/handlers.py +++ b/tests/project/api/handlers.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from piston.handler import BaseHandler diff --git a/tests/project/api/urls.py b/tests/project/api/urls.py index 9aa02d1..29dc30a 100644 --- a/tests/project/api/urls.py +++ b/tests/project/api/urls.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- '''URLs for the test API.''' +from __future__ import absolute_import from coffin.conf.urls.defaults import include, patterns from piston.authentication.oauth import OAuthAuthentication from piston.resource import Resource diff --git a/tests/project/manage.py b/tests/project/manage.py index e3945ea..0554876 100644 --- a/tests/project/manage.py +++ b/tests/project/manage.py @@ -1,7 +1,8 @@ #!/usr/bin/env python +from __future__ import absolute_import from django.core.management import execute_manager try: - import settings # Assumed to be in the same directory. + from . import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write('''\ diff --git a/tests/project/settings.py b/tests/project/settings.py index 0496c20..5aa249d 100644 --- a/tests/project/settings.py +++ b/tests/project/settings.py @@ -1,5 +1,6 @@ # Django settings for project project. +from __future__ import absolute_import import os DEBUG = True diff --git a/tests/project/urls.py b/tests/project/urls.py index 1a6daba..17252b9 100644 --- a/tests/project/urls.py +++ b/tests/project/urls.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.conf.urls.defaults import ( include, patterns, handler404 as default_handler404, handler500 as default_handler500) diff --git a/tests/ssl_urls.py b/tests/ssl_urls.py index 3e7b819..0d21e14 100644 --- a/tests/ssl_urls.py +++ b/tests/ssl_urls.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from coffin.conf.urls.defaults import patterns urlpatterns = patterns('test_ssl', diff --git a/tests/test_db_types.py b/tests/test_db_types.py index 0441bb8..41156d6 100644 --- a/tests/test_db_types.py +++ b/tests/test_db_types.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.models import Model from baph.db.orm import ORM from baph.db.types import UUID diff --git a/tests/test_models.py b/tests/test_models.py index bf47382..d9f9c7b 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.models import CustomPropsModel, Model from baph.db.orm import ORM from baph.test.base import TestCase from sqlalchemy import Column, Integer, String, Unicode from sqlalchemy.orm import synonym +import six orm = ORM.get() @@ -27,7 +29,7 @@ class TestModelWithProp(orm.Base, Model): @property def unicode_col(self): - return unicode(self.str_col) + return six.text_type(self.str_col) def to_dict(self): result = super(TestModelWithProp, self).to_dict() diff --git a/tests/test_orm.py b/tests/test_orm.py index 42a47cb..9b4af10 100644 --- a/tests/test_orm.py +++ b/tests/test_orm.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.db.orm import Mapify, ORM from baph.test.base import TestCase from django.conf import settings diff --git a/tests/test_sites.py b/tests/test_sites.py index bc03af1..b187db7 100644 --- a/tests/test_sites.py +++ b/tests/test_sites.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.sites.models import get_current_site, orm, RequestSite, Site from baph.test.base import TestCase from django.conf import settings diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 4abc380..a0eeeee 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.test.base import BaseTestCase from django.conf import settings from django.core.urlresolvers import reverse diff --git a/tests/utils/test_collections.py b/tests/utils/test_collections.py index 8643ad7..e4fce8c 100644 --- a/tests/utils/test_collections.py +++ b/tests/utils/test_collections.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.test.base import TestCase from baph.utils.collections import OrderedDefaultDict +import six class OrderedDefaultDictTestCase(TestCase): @@ -25,5 +27,5 @@ def test_simple(self): ('will-exist3', 7), ('will-exist4', 8), ] - self.assertEqual(d.items(), expected_items) - self.assertEqual([i for i in d.iteritems()], expected_items) + self.assertEqual(list(d.items()), expected_items) + self.assertEqual([i for i in six.iteritems(d)], expected_items) diff --git a/tests/utils/test_importing.py b/tests/utils/test_importing.py index e83bfcd..d6d2c22 100644 --- a/tests/utils/test_importing.py +++ b/tests/utils/test_importing.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.utils.importing import ( import_all_attrs, import_any_attr, import_any_module, import_attr) from baph.test.base import TestCase diff --git a/tests/utils/test_path.py b/tests/utils/test_path.py index 214d6ea..7fce20c 100644 --- a/tests/utils/test_path.py +++ b/tests/utils/test_path.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import from baph.test.base import TestCase from baph.utils.path import relpath import os