add compatibility with python 3 (#25486)

This commit is contained in:
Frédéric Péters 2018-07-25 14:28:05 +02:00
parent 9751386861
commit 67931d2d78
39 changed files with 133 additions and 98 deletions

View File

@ -16,6 +16,7 @@
from django import template
from django.db.models.fields.files import ImageFieldFile
from django.utils import six
from sorl.thumbnail.shortcuts import get_thumbnail
@ -36,7 +37,7 @@ def asset_url(*args, **kwargs):
asset = asset_object
break
if isinstance(asset_object, basestring):
if isinstance(asset_object, six.string_types):
try:
asset = Asset.objects.get(key=asset_object).asset
break

View File

@ -16,12 +16,11 @@
import datetime
import math
import urllib
from django.conf import settings
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.utils.dateparse import parse_datetime
from django.utils.http import urlencode
from django.utils.timezone import localtime, make_aware
from django.utils.translation import ugettext_lazy as _
@ -39,7 +38,7 @@ def get_wcs_services():
def get_chrono_service():
for chrono_key, chrono_site in get_services('chrono').iteritems():
for chrono_key, chrono_site in get_services('chrono').items():
if not chrono_site.get('secondary', True):
chrono_site['slug'] = chrono_key
return chrono_site
@ -128,7 +127,7 @@ def get_form_url_with_params(cell, data):
}
wcs_key, wcs_slug = cell.formdef_reference.split(':')
wcs = get_wcs_services().get(wcs_key)
url = '%s%s/?%s' % (wcs['url'], wcs_slug, urllib.urlencode(session_vars))
url = '%s%s/?%s' % (wcs['url'], wcs_slug, urlencode(session_vars))
return url
@ -189,7 +188,7 @@ class Calendar(object):
"""return the first available slot that has enough
consecutive available slots to be allowed for booking
"""
required_contiguous_slots = self.min_duration.seconds / self.offset.seconds
required_contiguous_slots = self.min_duration.seconds // self.offset.seconds
for day in self.days:
slots = day.slots
for idx in range(len(slots) - required_contiguous_slots):

View File

@ -16,6 +16,7 @@
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.utils.encoding import force_text
from django.views.generic import View, DetailView
from django.views.generic.detail import SingleObjectMixin
@ -36,7 +37,7 @@ class BookingView(SingleObjectMixin, View):
try:
form.is_valid()
except ValueError as exc:
messages.error(request, exc.message)
messages.error(request, force_text(exc))
redirect_url = '%s?%s' % (
cell.page.get_online_url(), request.GET.urlencode())
return HttpResponseRedirect(redirect_url)

View File

@ -21,7 +21,7 @@ from combo.utils import requests
def get_passerelle_service():
if hasattr(settings, 'KNOWN_SERVICES') and settings.KNOWN_SERVICES.get('passerelle'):
return settings.KNOWN_SERVICES['passerelle'].values()[0]
return list(settings.KNOWN_SERVICES['passerelle'].values())[0]
def is_family_enabled():
return get_passerelle_service() and hasattr(settings, 'FAMILY_SERVICE')

View File

@ -35,5 +35,5 @@ class Command(BaseCommand):
for regie in Regie.objects.exclude(webservice_url=''):
try:
regie.notify_new_remote_invoices()
except Exception, e:
except Exception as e:
logger.exception('error while notifying new remote invoices: %s', e)

View File

@ -20,6 +20,7 @@ from dateutil import parser as date_parser
from django.core.urlresolvers import reverse_lazy
from django.db.models import Q
from django.utils import six
from django.utils.timezone import make_aware
from django.views.generic import (CreateView, UpdateView, ListView,
DeleteView, TemplateView)
@ -93,7 +94,10 @@ def download_transactions_csv(request):
str(transaction.amount)]
for item in transaction.items.all():
row.extend([item.subject, str(item.amount)])
writer.writerow([unicode(x).encode('utf-8') for x in row])
if six.PY3:
writer.writerow([x for x in row])
else:
writer.writerow([unicode(x).encode('utf-8') for x in row])
return response

View File

@ -19,7 +19,6 @@
import datetime
import json
import logging
import urlparse
from decimal import Decimal
@ -36,8 +35,10 @@ from django.utils import timezone, dateparse
from django.core.mail import EmailMultiAlternatives
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.utils.encoding import python_2_unicode_compatible
from django.utils.formats import localize
from django.utils.http import urlencode
from django.utils.six.moves.urllib import parse as urlparse
from django.contrib.auth.models import User
from django.template.loader import render_to_string
@ -84,6 +85,7 @@ def build_remote_item(data, regie):
no_online_payment_reason=data.get('no_online_payment_reason'))
@python_2_unicode_compatible
class Regie(models.Model):
label = models.CharField(verbose_name=_('Label'), max_length=64)
slug = models.SlugField(unique=True, verbose_name=_('Identifier'),
@ -127,7 +129,7 @@ class Regie(models.Model):
def natural_key(self):
return (self.slug,)
def __unicode__(self):
def __str__(self):
return self.label
def get_text_on_success(self):
@ -271,7 +273,7 @@ class Regie(models.Model):
return
pending_invoices = self.get_remote_pending_invoices()
notification_ids = []
for uuid, items in pending_invoices.iteritems():
for uuid, items in pending_invoices.items():
try:
user = UserSAMLIdentifier.objects.get(name_id=uuid).user
except UserSAMLIdentifier.DoesNotExist:
@ -534,7 +536,7 @@ class LingoBasketCell(CellBase):
for items in regies.values():
items['total'] = sum([x.amount for x in items['items']])
context['regies'] = regies.values()
context['regies'] = sorted(regies.values(), key=lambda x: x['regie'].label)
return basket_template.render(context)

View File

@ -238,7 +238,7 @@ class ValidateTransactionApiView(View):
except eopayment.ResponseError as e:
logger.error(u'failed in validation operation: %s', e)
response = HttpResponse(content_type='application/json')
response.write(json.dumps({'err': 1, 'e': unicode(e)}))
response.write(json.dumps({'err': 1, 'e': force_text(e)}))
return response
logger.info(u'bank validation result: %r', result)
@ -279,7 +279,7 @@ class CancelTransactionApiView(View):
except eopayment.ResponseError as e:
logger.error(u'failed in cancel operation: %s', e)
response = HttpResponse(content_type='application/json')
response.write(json.dumps({'err': 1, 'e': unicode(e)}))
response.write(json.dumps({'err': 1, 'e': force_text(e)}))
return response
logger.info(u'bank cancellation result: %r', result)
@ -414,7 +414,7 @@ class PaymentView(View):
'eopayment_order_id': smart_text(payment_response.order_id),
'eopayment_response': repr(payment_response),
}
for k, v in payment_response.bank_data.iteritems():
for k, v in payment_response.bank_data.items():
extra_info['eopayment_bank_data_' + k] = smart_text(v)
if not payment_response.signed and not payment_response.result == eopayment.CANCELLED:
# we accept unsigned cancellation requests as some platforms do
@ -494,9 +494,9 @@ class CallbackView(PaymentView):
try:
self.handle_response(request, backend_response, **kwargs)
except UnknownPaymentException as e:
raise Http404(unicode(e))
raise Http404(force_text(e))
except PaymentException as e:
return HttpResponseBadRequest(unicode(e))
return HttpResponseBadRequest(force_text(e))
return HttpResponse()
def get(self, request, *args, **kwargs):

View File

@ -18,6 +18,8 @@ import json
from django.core import serializers
from django.db import models
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse_lazy
@ -88,6 +90,7 @@ class MapLayerManager(models.Manager):
return self.get(slug=slug)
@python_2_unicode_compatible
class MapLayer(models.Model):
objects = MapLayerManager()
@ -123,7 +126,7 @@ class MapLayer(models.Model):
self.slug = slug
super(MapLayer, self).save(*args, **kwargs)
def __unicode__(self):
def __str__(self):
return self.label
def natural_key(self):
@ -204,7 +207,7 @@ class MapLayer(models.Model):
def match(feature):
for geo_property in feature['properties'].values():
if not isinstance(geo_property, basestring):
if not isinstance(geo_property, six.string_types):
continue
if query in slugify(geo_property):
return True

View File

@ -14,13 +14,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from urlparse import urlparse
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db import connection
from django.test.client import RequestFactory
from django.utils import translation
from django.utils.six.moves.urllib.parse import urlparse
from combo.apps.momo.utils import generate_manifest, GenerationError, GenerationInfo
@ -46,5 +45,5 @@ class Command(BaseCommand):
raise CommandError(e.message)
except GenerationInfo as e:
if int(kwargs.get('verbosity')) > 0:
print e.message
print(e.message)
translation.deactivate()

View File

@ -84,7 +84,7 @@ class MomoIconCell(CellBase):
def get_default_form_class(self):
sorted_icons = self._meta.get_field('icon').choices
sorted_icons.sort(lambda x, y: cmp(x[1], y[1]))
sorted_icons.sort(key=lambda x: x[1])
return model_forms.modelform_factory(self.__class__,
fields=['icon', 'style', 'description', 'embed_page'],
widgets={'icon': Select(choices=sorted_icons)})

View File

@ -17,6 +17,7 @@
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.utils.encoding import force_text
from django.views.generic import TemplateView, UpdateView
from .models import MomoOptions
@ -30,9 +31,9 @@ def generate(request, **kwargs):
try:
generate_manifest(request)
except GenerationError as e:
messages.error(request, e.message)
messages.error(request, force_text(e))
except GenerationInfo as e:
messages.info(request, e.message)
messages.info(request, force_text(e))
return HttpResponseRedirect(reverse('momo-manager-homepage'))

View File

@ -33,7 +33,7 @@ class NewslettersManageForm(forms.Form):
self.cleaned_data = {}
try:
newsletters = self.instance.get_newsletters()
except Exception, e:
except Exception as e:
self.add_error(None, _('An error occured while getting newsletters. Please try later.'))
logger.error('Error occured while getting newsletters: %r', e)
return
@ -46,7 +46,7 @@ class NewslettersManageForm(forms.Form):
self.params['mobile'] = self.request.session['mellon_session'].get('mobile', '')
try:
subscriptions = self.instance.get_subscriptions(self.user, **self.params)
except Exception, e:
except Exception as e:
self.add_error(None, _('An error occured while getting subscriptions. Please try later.'))
logger.error('Error occured while getting subscriptions: %r', e)
return
@ -75,7 +75,7 @@ class NewslettersManageForm(forms.Form):
def save(self):
self.full_clean()
subscriptions = []
for key, value in self.cleaned_data.iteritems():
for key, value in self.cleaned_data.items():
subscriptions.append({
'id': key,
'transports': value

View File

@ -16,7 +16,6 @@
import logging
import json
import urlparse
from requests.exceptions import RequestException, HTTPError
@ -70,10 +69,10 @@ class NewslettersCell(CellBase):
return slugify(name.strip())
def get_resources_restrictions(self):
return filter(None, map(self.simplify, self.resources_restrictions.strip().split(',')))
return list(filter(None, map(self.simplify, self.resources_restrictions.strip().split(','))))
def get_transports_restrictions(self):
return filter(None, map(self.simplify, self.transports_restrictions.strip().split(',')))
return list(filter(None, map(self.simplify, self.transports_restrictions.strip().split(','))))
def check_resource(self, resource):
restrictions = self.get_resources_restrictions()
@ -130,7 +129,7 @@ class NewslettersCell(CellBase):
logger.error(u'set subscriptions on %s returned an HTTP error code: %s',
response.request.url, response.status_code)
raise SubscriptionsSaveError
except RequestException, e:
except RequestException as e:
logger.error(u'set subscriptions on %s failed with exception: %s',
endpoint, e)
raise SubscriptionsSaveError

View File

@ -14,6 +14,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.utils.encoding import force_text
from rest_framework import serializers, permissions, status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
@ -55,7 +57,7 @@ class Add(GenericAPIView):
duration=data.get('duration'),
)
except ValueError as e:
response = {'err': 1, 'err_desc': {'id': [unicode(e)]}}
response = {'err': 1, 'err_desc': {'id': [force_text(e)]}}
return Response(response, status.HTTP_400_BAD_REQUEST)
else:
response = {'err': 0, 'data': {'id': notification.public_id}}

View File

@ -18,6 +18,7 @@ import re
from django.conf import settings
from django.db import models
from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now, timedelta
from django.db.models import Q
@ -61,6 +62,7 @@ class NotificationQuerySet(QuerySet):
end_timestamp=past_end_timestamp, acked=True)
@python_2_unicode_compatible
class Notification(models.Model):
ID_RE = r'^[\w-]+:[\w-]+$'
@ -82,7 +84,7 @@ class Notification(models.Model):
('user', 'external_id'),
)
def __unicode__(self):
def __str__(self):
return self.summary
@property
@ -136,7 +138,7 @@ class Notification(models.Model):
if id:
try:
id = unicode(id)
id = force_text(id)
except Exception as e:
raise ValueError('id must be convertible to unicode', e)
if not re.match(cls.ID_RE, id):

View File

@ -500,6 +500,6 @@ class TrackingCodeInputCell(CellBase):
def get_cell_extra_context(self, context):
extra_context = super(TrackingCodeInputCell, self).get_cell_extra_context(context)
if not self.wcs_site:
self.wcs_site = get_wcs_services().keys()[0]
self.wcs_site = list(get_wcs_services().keys())[0]
extra_context['url'] = get_wcs_services().get(self.wcs_site).get('url')
return extra_context

View File

@ -1,7 +1,7 @@
{% load i18n combo %}
{% block cell-content %}
<h2>{% trans 'Current Drafts' %}</h2>
{% for slug, forms in current_drafts.iteritems %}
{% for slug, forms in current_drafts.items %}
<div class="current-drafts-{{ slug }} current-drafts list-of-forms">
{% if forms.data %}
<ul>

View File

@ -1,7 +1,7 @@
{% load i18n %}
{% block cell-content %}
<h2>{% trans 'Current Forms' %}</h2>
{% for slug, forms in current_forms.iteritems %}
{% for slug, forms in current_forms.items %}
<div class="current-forms-{{ slug }} current-forms list-of-forms">
{% include "combo/wcs/list_of_forms.html" with forms=forms %}
</div>

View File

@ -1,7 +1,7 @@
{% load i18n %}
{% block cell-content %}
<h2>{% trans 'Form Categories' %}</h2>
{% for slug, categories in form_categories.iteritems %}
{% for slug, categories in form_categories.items %}
<div class="categories-{{ slug }}">
<h3>{{ categories.title }}</h3>
<ul>

View File

@ -1,7 +1,7 @@
{% load combo i18n %}
{% block cell-content %}
<h2>{% trans 'All Forms' %}</h2>
{% for slug, forms in user_forms.iteritems %}
{% for slug, forms in user_forms.items %}
<div class="user-forms-{{ slug }} user-all-forms list-of-forms">
{% include "combo/wcs/list_of_forms.html" with forms=forms %}
</div>

View File

@ -1,7 +1,7 @@
{% load combo i18n %}
{% block cell-content %}
<h2>{% trans 'Done Forms' %}</h2>
{% for slug, forms in user_forms.iteritems %}
{% for slug, forms in user_forms.items %}
<div class="user-forms-{{ slug }} list-of-forms">
{% include "combo/wcs/list_of_forms.html" with forms=forms %}
</div>

View File

@ -32,7 +32,7 @@ def get_wcs_json(wcs_site, path):
def get_wcs_options(url, include_category_slug=False):
references = []
for wcs_key, wcs_site in get_wcs_services().iteritems():
for wcs_key, wcs_site in get_wcs_services().items():
site_title = wcs_site.get('title')
response_json = get_wcs_json(wcs_site, url)
if type(response_json) is dict:
@ -51,5 +51,5 @@ def get_wcs_options(url, include_category_slug=False):
else:
reference = '%s:%s' % (wcs_key, slug)
references.append((reference, label))
references.sort(lambda x, y: cmp(x[1], y[1]))
references.sort(key=lambda x: x[1])
return references

View File

@ -14,10 +14,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import urlparse
from django.contrib import messages
from django.http import HttpResponseRedirect, HttpResponseBadRequest
from django.http import HttpResponseRedirect
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View

View File

@ -18,6 +18,7 @@ import json
import sys
from django.core.management.base import BaseCommand
from django.utils.encoding import force_text
from combo.data.utils import import_site, MissingGroups
@ -44,4 +45,4 @@ class Command(BaseCommand):
if_empty=options['if_empty'],
clean=options['clean'])
except MissingGroups as e:
print >> sys.stderr, unicode(e)
sys.stderr.write(force_text(e) + '\n')

View File

@ -24,7 +24,6 @@ import os
import re
import requests
import subprocess
import urlparse
from django.apps import apps
from django.conf import settings
@ -40,9 +39,11 @@ from django.dispatch import receiver
from django.forms import models as model_forms
from django import forms
from django import template
from django.utils.encoding import force_text
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible, force_text, smart_bytes
from django.utils.html import strip_tags
from django.utils.safestring import mark_safe
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from django.forms.widgets import MediaDefiningClass
@ -116,6 +117,7 @@ class PageManager(models.Manager):
return queryset.filter(snapshot__isnull=True)
@python_2_unicode_compatible
class Page(models.Model):
objects = PageManager()
snapshots = PageManager(snapshots=True)
@ -149,7 +151,7 @@ class Page(models.Model):
class Meta:
ordering = ['order']
def __unicode__(self):
def __str__(self):
return self.title
def natural_key(self):
@ -349,7 +351,7 @@ class Page(models.Model):
del cell['pk']
del cell['fields']['page']
cell['fields']['groups'] = [x[0] for x in cell['fields']['groups']]
for key in cell['fields'].keys():
for key in list(cell['fields'].keys()):
if key.startswith('cached_'):
del cell['fields'][key]
return serialized_page
@ -357,14 +359,14 @@ class Page(models.Model):
@classmethod
def load_serialized_page(cls, json_page, snapshot=None):
json_page['model'] = 'data.page'
json_page['fields']['groups'] = [[x] for x in json_page['fields']['groups'] if isinstance(x, basestring)]
json_page['fields']['groups'] = [[x] for x in json_page['fields']['groups'] if isinstance(x, six.string_types)]
page, created = Page.objects.get_or_create(slug=json_page['fields']['slug'], snapshot=snapshot)
json_page['pk'] = page.id
page = [x for x in serializers.deserialize('json', json.dumps([json_page]))][0]
page.object.snapshot = snapshot
page.save()
for cell in json_page.get('cells'):
cell['fields']['groups'] = [[x] for x in cell['fields']['groups'] if isinstance(x, basestring)]
cell['fields']['groups'] = [[x] for x in cell['fields']['groups'] if isinstance(x, six.string_types)]
if snapshot:
cell['fields']['page'] = page.object.id
else:
@ -462,8 +464,8 @@ class CellMeta(MediaDefiningClass, ModelBase):
pass
class CellBase(models.Model):
__metaclass__ = CellMeta
@python_2_unicode_compatible
class CellBase(six.with_metaclass(CellMeta, models.Model)):
page = models.ForeignKey(Page)
placeholder = models.CharField(max_length=20)
@ -499,13 +501,13 @@ class CellBase(models.Model):
class Meta:
abstract = True
def __unicode__(self):
label = unicode(self.get_verbose_name())
def __str__(self):
label = self.get_verbose_name()
additional_label = self.get_additional_label()
if label and additional_label:
return '%s (%s)' % (label, re.sub(r'\r?\n', ' ', force_text(additional_label)))
return u'%s (%s)' % (label, re.sub(r'\r?\n', u' ', force_text(additional_label)))
else:
return label
return force_text(label)
@classmethod
def get_verbose_name(cls):
@ -561,7 +563,7 @@ class CellBase(models.Model):
if cell_filter and not cell_filter(klass):
continue
cells.extend(klass.objects.filter(**kwargs))
cells.sort(lambda x, y: cmp(x.order, y.order))
cells.sort(key=lambda x: x.order)
return cells
def get_reference(self):
@ -699,7 +701,7 @@ class CellBase(models.Model):
}
if not self.is_relevant(context):
return ''
from HTMLParser import HTMLParser
from django.utils.six.moves.html_parser import HTMLParser
return HTMLParser().unescape(strip_tags(self.render(context)))
def get_external_links_data(self):
@ -832,7 +834,7 @@ class LinkCell(CellBase):
return context
def get_default_form_class(self):
from forms import LinkCellForm
from .forms import LinkCellForm
return LinkCellForm
def render_for_search(self):
@ -867,7 +869,7 @@ class FeedCell(CellBase):
if context.get('placeholder_search_mode'):
# don't call webservices when we're just looking for placeholders
return extra_context
cache_key = hashlib.md5(self.url).hexdigest()
cache_key = hashlib.md5(smart_bytes(self.url)).hexdigest()
feed_content = cache.get(cache_key)
if not feed_content:
feed_response = requests.get(utils.get_templated_url(self.url))
@ -886,7 +888,7 @@ class FeedCell(CellBase):
return extra_context
def render(self, context):
cache_key = hashlib.md5(self.url).hexdigest()
cache_key = hashlib.md5(smart_bytes(self.url)).hexdigest()
feed_content = cache.get(cache_key)
if not context.get('synchronous') and feed_content is None:
raise NothingInCacheException()
@ -1091,13 +1093,13 @@ class JsonCellBase(CellBase):
)
except requests.RequestException as e:
extra_context[data_key + '_status'] = -1
extra_context[data_key + '_error'] = unicode(e)
extra_context[data_key + '_error'] = force_text(e)
extra_context[data_key + '_exception'] = e
logger = logging.getLogger(__name__)
if log_errors:
logger.warning(u'error on request %r: %s', url, unicode(e))
logger.warning(u'error on request %r: %s', url, force_text(e))
else:
logger.debug(u'error on request %r: %s', url, unicode(e))
logger.debug(u'error on request %r: %s', url, force_text(e))
continue
extra_context[data_key + '_status'] = json_response.status_code
if json_response.status_code // 100 == 2:
@ -1243,7 +1245,7 @@ class ConfigJsonCell(JsonCellBase):
'group': _('Extra'),
'cell_type_str': cls.get_cell_type_str(),
})
l.sort(lambda x, y: cmp(x.get('name'), y.get('name')))
l.sort(key=lambda x: x.get('name'))
return l
def get_label(self):

View File

@ -16,6 +16,8 @@
from django.contrib.auth.models import Group
from django.db import transaction
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from combo.apps.assets.models import Asset
@ -23,11 +25,12 @@ from combo.apps.maps.models import MapLayer
from .models import Page
@python_2_unicode_compatible
class MissingGroups(Exception):
def __init__(self, names):
self.names = names
def __unicode__(self):
def __str__(self):
return _('Missing groups: %s') % ', '.join(self.names)
@ -51,10 +54,10 @@ def import_site(data, if_empty=False, clean=False):
groups = set()
for page in data.get('pages') or []:
for group in page['fields']['groups']:
groups.add(group if isinstance(group, basestring) else group[0])
groups.add(group if isinstance(group, six.string_types) else group[0])
for cell in page['cells']:
for group in cell['fields']['groups']:
groups.add(group if isinstance(group, basestring) else group[0])
groups.add(group if isinstance(group, six.string_types) else group[0])
existing_groups = set([x.name for x in Group.objects.filter(name__in=groups)])
missing_groups = groups - existing_groups

View File

@ -69,7 +69,7 @@ class PageSelectTemplateForm(forms.ModelForm):
super(PageSelectTemplateForm, self).__init__(*args, **kwargs)
templates = [(x[0], x[1]['name']) for x in settings.COMBO_PUBLIC_TEMPLATES.items()]
templates = [x for x in templates if self.template_exists(x[0])]
templates.sort(lambda x, y: cmp(x[1], y[1]))
templates.sort(key=lambda x: x[1])
if 'template_name' in self.fields:
self.fields['template_name'].widget = forms.Select(choices=templates)

View File

@ -237,7 +237,7 @@ class PageView(DetailView):
if 'data' in cell_type_groups.keys():
cell_type_groups[''] = cell_type_groups.get('data')
del cell_type_groups['data']
context['cell_type_groups'] = cell_type_groups.items()
context['cell_type_groups'] = list(cell_type_groups.items())
context['cell_type_groups'].sort(key=lambda x: x[0])
cells = CellBase.get_cells(page_id=self.object.id)

View File

@ -220,3 +220,7 @@ def get_group(group_list, group_name):
@register.filter(name='is_empty_placeholder')
def is_empty_placeholder(page, placeholder_name):
return len([x for x in page.get_cells() if x.placeholder == placeholder_name]) == 0
@register.filter(name='list')
def as_list(obj):
return list(obj)

View File

@ -15,8 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import urllib
import urlparse
import django
from django.conf import settings
@ -31,6 +29,9 @@ from django.shortcuts import render, resolve_url
from django.template import engines
from django.template.loader import get_template, TemplateDoesNotExist
from django.utils import lorem_ipsum, timezone
from django.utils.encoding import force_text
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.six.moves.urllib import parse as urllib
from django.views.decorators.csrf import csrf_exempt
from django.utils.translation import ugettext as _
@ -102,14 +103,14 @@ def ajax_page_cell(request, page_pk, cell_reference):
except PostException as e:
exception = e
if not request.is_ajax():
messages.error(request, e.message or _('Error sending data.'))
messages.error(request, force_text(e) if force_text(e) != 'None' else _('Error sending data.'))
if not request.is_ajax():
return HttpResponseRedirect(cell.page.get_online_url())
response = render_cell(request, cell)
if exception:
response['x-error-message'] = exception.message
response['x-error-message'] = force_text(exception)
return response
def render_cell(request, cell):

View File

@ -315,4 +315,4 @@ NEWSLETTERS_CELL_ENABLED = False
local_settings_file = os.environ.get('COMBO_SETTINGS_FILE',
os.path.join(os.path.dirname(__file__), 'local_settings.py'))
if os.path.exists(local_settings_file):
execfile(local_settings_file)
exec(open(local_settings_file).read())

View File

@ -20,6 +20,9 @@ from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto import Random
from django.utils import six
from django.utils.encoding import force_text
class DecryptionError(Exception):
pass
@ -33,7 +36,7 @@ def aes_hex_encrypt(key, data):
aes_key = PBKDF2(key, iv)
aes = AES.new(aes_key, AES.MODE_CFB, iv)
crypted = aes.encrypt(data)
return '%s%s' % (binascii.hexlify(iv[:2]), binascii.hexlify(crypted))
return force_text(b'%s%s' % (binascii.hexlify(iv[:2]), binascii.hexlify(crypted)))
def aes_hex_decrypt(key, payload, raise_on_error=True):
'''Decrypt data encrypted with aes_base64_encrypt'''
@ -46,10 +49,10 @@ def aes_hex_decrypt(key, payload, raise_on_error=True):
try:
iv = binascii.unhexlify(iv) * 8
crypted = binascii.unhexlify(crypted)
except TypeError:
except (TypeError, binascii.Error):
if raise_on_error:
raise DecryptionError('incorrect hexadecimal encoding')
return None
aes_key = PBKDF2(key, iv)
aes = AES.new(aes_key, AES.MODE_CFB, iv)
return aes.decrypt(crypted)
return force_text(aes.decrypt(crypted), 'utf-8')

View File

@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from HTMLParser import HTMLParser
from django.utils.six.moves.html_parser import HTMLParser
from django.template.context import BaseContext
from django.utils.html import strip_tags

View File

@ -16,8 +16,6 @@
import hashlib
import logging
from StringIO import StringIO
import urlparse
from requests import Response, Session as RequestsSession
@ -25,6 +23,8 @@ from django.conf import settings
from django.core.cache import cache
from django.utils.encoding import smart_bytes
from django.utils.http import urlencode
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.six import BytesIO
from .signature import sign_url
@ -110,7 +110,7 @@ class Requests(RequestsSession):
if cache_content and not invalidate_cache:
response = Response()
response.status_code = 200
response.raw = StringIO(cache_content)
response.raw = BytesIO(smart_bytes(cache_content))
return response
elif raise_if_not_cached:
raise NothingInCacheException()

View File

@ -19,10 +19,13 @@ import datetime
import hmac
import hashlib
import random
import urlparse
from django.conf import settings
from django.utils.encoding import smart_bytes
from django.utils.http import quote, urlencode
from django.utils import six
from django.utils.six.moves.urllib import parse as urlparse
# Simple signature scheme for query strings
@ -50,7 +53,7 @@ def sign_query(query, key, algo='sha256', timestamp=None, nonce=None):
def sign_string(s, key, algo='sha256', timedelta=30):
digestmod = getattr(hashlib, algo)
hash = hmac.HMAC(str(key), digestmod=digestmod, msg=s)
hash = hmac.HMAC(smart_bytes(key), digestmod=digestmod, msg=smart_bytes(s))
return hash.digest()
def check_request_signature(django_request, keys=[]):
@ -60,8 +63,8 @@ def check_request_signature(django_request, keys=[]):
orig = django_request.GET.get('orig', '')
known_services = getattr(settings, 'KNOWN_SERVICES', None)
if known_services and orig:
for services in known_services.itervalues():
for service in services.itervalues():
for services in known_services.values():
for service in services.values():
if 'verif_orig' in service and service['verif_orig'] == orig:
keys.append(service['secret'])
break
@ -95,8 +98,12 @@ def check_string(s, signature, keys, algo='sha256'):
continue
res = 0
# constant time compare
for a, b in zip(signature, signature2):
res |= ord(a) ^ ord(b)
if six.PY3:
for a, b in zip(signature, signature2):
res |= a ^ b
else:
for a, b in zip(signature, signature2):
res |= ord(a) ^ ord(b)
if res == 0:
return True
return False

View File

@ -17,6 +17,7 @@
import re
from django.conf import settings
from django.utils.encoding import force_text
from django.template import Context, Template, TemplateSyntaxError, VariableDoesNotExist
from django.utils.http import quote
@ -58,5 +59,5 @@ def get_templated_url(url, context=None):
return '['
if varname not in template_vars:
raise TemplateError('unknown variable %s', varname)
return unicode(template_vars[varname])
return force_text(template_vars[varname])
return re.sub(r'(\[.+?\])', repl, url)

View File

@ -36,7 +36,7 @@ def get_version():
p = subprocess.Popen(['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE)
result = p.communicate()[0]
if p.returncode == 0:
version = result.split()[0][1:]
version = str(result.split()[0][1:])
version = version.replace('-', '.')
return version
return '0'

View File

@ -1,12 +1,12 @@
[tox]
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/combo/{env:BRANCH_NAME:}
envlist = django{18,111}
envlist = py2-django18,coverage-py2-django111-pylint,py3-django111
[testenv]
usedevelop = True
basepython = python2
setenv =
WCSCTL=wcs/wcsctl.py
py2: WCSCTL=wcs/wcsctl.py
DJANGO_SETTINGS_MODULE=combo.settings
COMBO_SETTINGS_FILE=tests/settings.py
deps =
@ -22,10 +22,10 @@ deps =
pylint<1.8
pylint-django<0.9
django-webtest<1.9.3
quixote<3.0
vobject
psycopg2
django-mellon
py2: quixote<3.0
py2: vobject
commands =
./getlasso.sh
python manage.py compilemessages