Remove all usage of 'six' and as much compat code as I could f… (#11730)
* Remove all usage of 'six' and as much compat code as I could find. Cleans up some imports along the way. Fixes #11728 * Fix typo * Fix rta related code paths, I actually misread the comment… * Move ResourceWarning filtering to setup.cfg
This commit is contained in:
Родитель
17d4886b14
Коммит
2de22598bd
|
@ -10,7 +10,6 @@ import warnings
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import responses
|
import responses
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
|
@ -138,11 +137,6 @@ def test_pre_setup(request, tmpdir, settings):
|
||||||
from waffle.utils import get_cache as waffle_get_cache
|
from waffle.utils import get_cache as waffle_get_cache
|
||||||
from waffle import models as waffle_models
|
from waffle import models as waffle_models
|
||||||
|
|
||||||
# Ignore ResourceWarning for now. It's a Python 3 thing so it's done
|
|
||||||
# dynamically here.
|
|
||||||
if six.PY3:
|
|
||||||
warnings.filterwarnings('ignore', category=ResourceWarning) # noqa
|
|
||||||
|
|
||||||
# Clear all cache-instances. They'll be re-initialized by Django
|
# Clear all cache-instances. They'll be re-initialized by Django
|
||||||
# This will make sure that our random `KEY_PREFIX` is applied
|
# This will make sure that our random `KEY_PREFIX` is applied
|
||||||
# appropriately.
|
# appropriately.
|
||||||
|
|
|
@ -3,7 +3,7 @@ Turn :src:`file.py` into a link to `file.py` in your online source browser.
|
||||||
|
|
||||||
Requires src_base_url to be set in conf.py.
|
Requires src_base_url to be set in conf.py.
|
||||||
"""
|
"""
|
||||||
from six.moves.urllib_parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import sys
|
||||||
|
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from email.utils import formatdate
|
from email.utils import formatdate
|
||||||
from six.moves.urllib.parse import parse_qsl
|
from urllib.parse import parse_qsl
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from services.utils import (
|
from services.utils import (
|
||||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
||||||
import MySQLdb as mysql
|
import MySQLdb as mysql
|
||||||
import sqlalchemy.pool as pool
|
import sqlalchemy.pool as pool
|
||||||
|
|
||||||
from six.moves.urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from services.settings import settings
|
from services.settings import settings
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ won't be tracked in git).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from six.moves.urllib_parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from olympia.lib.settings_base import * # noqa
|
from olympia.lib.settings_base import * # noqa
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ DJANGO_SETTINGS_MODULE = settings_test
|
||||||
filterwarnings =
|
filterwarnings =
|
||||||
default
|
default
|
||||||
ignore:::csp.utils
|
ignore:::csp.utils
|
||||||
|
# Ignore ResourceWarning for now. It's a Python 3 thing :-/
|
||||||
|
ignore::ResourceWarning
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = F999,F405,W504
|
ignore = F999,F405,W504
|
||||||
|
|
|
@ -4,9 +4,6 @@ from django.contrib.gis.geoip2 import GeoIP2, GeoIP2Exception
|
||||||
from django.core.validators import validate_ipv46_address
|
from django.core.validators import validate_ipv46_address
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from extended_choices import Choices
|
from extended_choices import Choices
|
||||||
from geoip2.errors import GeoIP2Error
|
from geoip2.errors import GeoIP2Error
|
||||||
|
@ -34,7 +31,6 @@ class AbuseReportManager(ManagerBase):
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class AbuseReport(ModelBase):
|
class AbuseReport(ModelBase):
|
||||||
# Note: those choices don't need to be translated for now, the
|
# Note: those choices don't need to be translated for now, the
|
||||||
# human-readable values are only exposed in the admin.
|
# human-readable values are only exposed in the admin.
|
||||||
|
@ -188,8 +184,7 @@ class AbuseReport(ModelBase):
|
||||||
)
|
)
|
||||||
msg = '%s reported abuse for %s (%s).\n\n%s\n\n%s' % (
|
msg = '%s reported abuse for %s (%s).\n\n%s\n\n%s' % (
|
||||||
user_name, target_name, target_url, metadata, self.message)
|
user_name, target_name, target_url, metadata, self.message)
|
||||||
send_mail(
|
send_mail(str(self), msg, recipient_list=(settings.ABUSE_EMAIL,))
|
||||||
six.text_type(self), msg, recipient_list=(settings.ABUSE_EMAIL,))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def metadata(self):
|
def metadata(self):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
|
from urllib.parse import parse_qsl, urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
@ -9,7 +10,6 @@ from django.test import RequestFactory
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from six.moves.urllib_parse import parse_qsl, urlparse
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.abuse.admin import AbuseReportAdmin
|
from olympia.abuse.admin import AbuseReportAdmin
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.abuse.models import AbuseReport, GeoIP2Error, GeoIP2Exception
|
from olympia.abuse.models import AbuseReport, GeoIP2Error, GeoIP2Exception
|
||||||
from olympia.addons.models import Addon
|
from olympia.addons.models import Addon
|
||||||
from olympia.amo.tests import addon_factory, TestCase
|
from olympia.amo.tests import addon_factory, TestCase
|
||||||
|
@ -123,9 +122,7 @@ class TestAbuse(TestCase):
|
||||||
user = UserProfile.objects.get(pk=999)
|
user = UserProfile.objects.get(pk=999)
|
||||||
report = AbuseReport.objects.create(user=user)
|
report = AbuseReport.objects.create(user=user)
|
||||||
report.send()
|
report.send()
|
||||||
assert (
|
assert str(report) == u'[User] Abuse Report for regularuser التطب'
|
||||||
six.text_type(report) ==
|
|
||||||
u'[User] Abuse Report for regularuser التطب')
|
|
||||||
assert (
|
assert (
|
||||||
mail.outbox[0].subject ==
|
mail.outbox[0].subject ==
|
||||||
u'[User] Abuse Report for regularuser التطب')
|
u'[User] Abuse Report for regularuser التطب')
|
||||||
|
@ -137,7 +134,7 @@ class TestAbuse(TestCase):
|
||||||
addon = Addon.objects.get(pk=3615)
|
addon = Addon.objects.get(pk=3615)
|
||||||
report = AbuseReport.objects.create(addon=addon)
|
report = AbuseReport.objects.create(addon=addon)
|
||||||
assert (
|
assert (
|
||||||
six.text_type(report) ==
|
str(report) ==
|
||||||
u'[Extension] Abuse Report for Delicious Bookmarks')
|
u'[Extension] Abuse Report for Delicious Bookmarks')
|
||||||
report.send()
|
report.send()
|
||||||
assert (
|
assert (
|
||||||
|
@ -184,7 +181,7 @@ reason => Damages computer and/or data
|
||||||
with self.activate(locale='fr'):
|
with self.activate(locale='fr'):
|
||||||
report = AbuseReport(addon_id=3615)
|
report = AbuseReport(addon_id=3615)
|
||||||
assert (
|
assert (
|
||||||
six.text_type(report) ==
|
str(report) ==
|
||||||
u'[Extension] Abuse Report for Delicious Bookmarks')
|
u'[Extension] Abuse Report for Delicious Bookmarks')
|
||||||
report.send()
|
report.send()
|
||||||
assert (
|
assert (
|
||||||
|
@ -194,9 +191,7 @@ reason => Damages computer and/or data
|
||||||
def test_guid(self):
|
def test_guid(self):
|
||||||
report = AbuseReport.objects.create(guid='foo@bar.org')
|
report = AbuseReport.objects.create(guid='foo@bar.org')
|
||||||
report.send()
|
report.send()
|
||||||
assert (
|
assert str(report) == u'[Addon] Abuse Report for foo@bar.org'
|
||||||
six.text_type(report) ==
|
|
||||||
u'[Addon] Abuse Report for foo@bar.org')
|
|
||||||
assert (
|
assert (
|
||||||
mail.outbox[0].subject ==
|
mail.outbox[0].subject ==
|
||||||
u'[Addon] Abuse Report for foo@bar.org')
|
u'[Addon] Abuse Report for foo@bar.org')
|
||||||
|
|
|
@ -5,7 +5,6 @@ from datetime import datetime
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.abuse.models import AbuseReport
|
from olympia.abuse.models import AbuseReport
|
||||||
|
@ -27,7 +26,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def check_report(self, report, text):
|
def check_report(self, report, text):
|
||||||
assert six.text_type(report) == text
|
assert str(report) == text
|
||||||
assert report.country_code == 'ZZ'
|
assert report.country_code == 'ZZ'
|
||||||
assert mail.outbox[0].subject == text
|
assert mail.outbox[0].subject == text
|
||||||
self.check_reporter(report)
|
self.check_reporter(report)
|
||||||
|
@ -36,7 +35,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
addon = addon_factory()
|
addon = addon_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id), 'message': 'abuse!'},
|
data={'addon': str(addon.id), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
@ -101,7 +100,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
addon = addon_factory(status=amo.STATUS_NULL)
|
addon = addon_factory(status=amo.STATUS_NULL)
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id), 'message': 'abuse!'},
|
data={'addon': str(addon.id), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
addon = addon_factory()
|
addon = addon_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id),
|
data={'addon': str(addon.id),
|
||||||
'message': ''})
|
'message': ''})
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert json.loads(response.content) == {
|
assert json.loads(response.content) == {
|
||||||
|
@ -133,7 +132,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
addon = addon_factory()
|
addon = addon_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id)})
|
data={'addon': str(addon.id)})
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert json.loads(response.content) == {
|
assert json.loads(response.content) == {
|
||||||
'message': ['This field is required.']}
|
'message': ['This field is required.']}
|
||||||
|
@ -142,7 +141,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
addon = addon_factory()
|
addon = addon_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id), 'reason': 'broken'},
|
data={'addon': str(addon.id), 'reason': 'broken'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
@ -156,7 +155,7 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
addon = addon_factory()
|
addon = addon_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id), 'reason': 'broken',
|
data={'addon': str(addon.id), 'reason': 'broken',
|
||||||
'message': ''},
|
'message': ''},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
@ -172,13 +171,13 @@ class AddonAbuseViewSetTestBase(object):
|
||||||
for x in range(20):
|
for x in range(20):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id), 'message': 'abuse!'},
|
data={'addon': str(addon.id), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201, x
|
assert response.status_code == 201, x
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'addon': six.text_type(addon.id), 'message': 'abuse!'},
|
data={'addon': str(addon.id), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 429
|
assert response.status_code == 429
|
||||||
|
|
||||||
|
@ -306,7 +305,7 @@ class UserAbuseViewSetTestBase(object):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def check_report(self, report, text):
|
def check_report(self, report, text):
|
||||||
assert six.text_type(report) == text
|
assert str(report) == text
|
||||||
assert report.country_code == 'ZZ'
|
assert report.country_code == 'ZZ'
|
||||||
assert mail.outbox[0].subject == text
|
assert mail.outbox[0].subject == text
|
||||||
self.check_reporter(report)
|
self.check_reporter(report)
|
||||||
|
@ -315,7 +314,7 @@ class UserAbuseViewSetTestBase(object):
|
||||||
user = user_factory()
|
user = user_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'user': six.text_type(user.id), 'message': 'abuse!'},
|
data={'user': str(user.id), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
@ -328,7 +327,7 @@ class UserAbuseViewSetTestBase(object):
|
||||||
user = user_factory()
|
user = user_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'user': six.text_type(user.username), 'message': 'abuse!'},
|
data={'user': str(user.username), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
@ -349,7 +348,7 @@ class UserAbuseViewSetTestBase(object):
|
||||||
user = user_factory()
|
user = user_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'user': six.text_type(user.username), 'message': ''})
|
data={'user': str(user.username), 'message': ''})
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert json.loads(response.content) == {
|
assert json.loads(response.content) == {
|
||||||
'message': ['This field may not be blank.']}
|
'message': ['This field may not be blank.']}
|
||||||
|
@ -358,7 +357,7 @@ class UserAbuseViewSetTestBase(object):
|
||||||
user = user_factory()
|
user = user_factory()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'user': six.text_type(user.username)})
|
data={'user': str(user.username)})
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert json.loads(response.content) == {
|
assert json.loads(response.content) == {
|
||||||
'message': ['This field is required.']}
|
'message': ['This field is required.']}
|
||||||
|
@ -368,14 +367,14 @@ class UserAbuseViewSetTestBase(object):
|
||||||
for x in range(20):
|
for x in range(20):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'user': six.text_type(
|
data={'user': str(
|
||||||
user.username), 'message': 'abuse!'},
|
user.username), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 201, x
|
assert response.status_code == 201, x
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.url,
|
self.url,
|
||||||
data={'user': six.text_type(user.username), 'message': 'abuse!'},
|
data={'user': str(user.username), 'message': 'abuse!'},
|
||||||
REMOTE_ADDR='123.45.67.89')
|
REMOTE_ADDR='123.45.67.89')
|
||||||
assert response.status_code == 429
|
assert response.status_code == 429
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django import dispatch
|
from django import dispatch
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
|
|
||||||
import olympia.core.logger
|
import olympia.core.logger
|
||||||
|
|
||||||
|
@ -13,7 +12,6 @@ from olympia.amo.models import ModelBase
|
||||||
log = olympia.core.logger.getLogger('z.users')
|
log = olympia.core.logger.getLogger('z.users')
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Group(ModelBase):
|
class Group(ModelBase):
|
||||||
# If `id` is changed from PositiveAutoField, update TestPositiveAutoField.
|
# If `id` is changed from PositiveAutoField, update TestPositiveAutoField.
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
|
|
|
@ -2,8 +2,6 @@ from django.conf import settings
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
import olympia.core.logger
|
import olympia.core.logger
|
||||||
|
@ -108,7 +106,7 @@ class UserProfileSerializer(PublicUserProfileSerializer):
|
||||||
entrypoint='addons')
|
entrypoint='addons')
|
||||||
|
|
||||||
def validate_biography(self, value):
|
def validate_biography(self, value):
|
||||||
if has_links(clean_nl(six.text_type(value))):
|
if has_links(clean_nl(str(value))):
|
||||||
# There's some links, we don't want them.
|
# There's some links, we don't want them.
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
ugettext(u'No links are allowed.'))
|
ugettext(u'No links are allowed.'))
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.test import APIRequestFactory
|
from rest_framework.test import APIRequestFactory
|
||||||
|
|
||||||
|
@ -97,7 +95,7 @@ class TestPublicUserProfileSerializer(TestCase):
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
data = self.serialize()
|
data = self.serialize()
|
||||||
for prop, val in self.user_kwargs.items():
|
for prop, val in self.user_kwargs.items():
|
||||||
assert data[prop] == six.text_type(val), prop
|
assert data[prop] == str(val), prop
|
||||||
for prop, val in self.user_private_kwargs.items():
|
for prop, val in self.user_private_kwargs.items():
|
||||||
assert prop not in data
|
assert prop not in data
|
||||||
return data
|
return data
|
||||||
|
@ -211,10 +209,10 @@ class TestUserProfileSerializer(TestPublicUserProfileSerializer,
|
||||||
self.grant_permission(self.user, 'Addons:PostReview')
|
self.grant_permission(self.user, 'Addons:PostReview')
|
||||||
data = self.serialize()
|
data = self.serialize()
|
||||||
for prop, val in self.user_kwargs.items():
|
for prop, val in self.user_kwargs.items():
|
||||||
assert data[prop] == six.text_type(val), prop
|
assert data[prop] == str(val), prop
|
||||||
# We can also see private stuff, it's the same user.
|
# We can also see private stuff, it's the same user.
|
||||||
for prop, val in self.user_private_kwargs.items():
|
for prop, val in self.user_private_kwargs.items():
|
||||||
assert data[prop] == six.text_type(val), prop
|
assert data[prop] == str(val), prop
|
||||||
|
|
||||||
def test_expose_fxa_edit_email_url(self):
|
def test_expose_fxa_edit_email_url(self):
|
||||||
fxa_host = 'http://example.com'
|
fxa_host = 'http://example.com'
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
from unittest import mock
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from base64 import urlsafe_b64decode, urlsafe_b64encode
|
from base64 import urlsafe_b64decode, urlsafe_b64encode
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from six.moves.urllib_parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
from six.moves.urllib_parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -1150,7 +1149,7 @@ class TestAccountViewSetUpdate(TestCase):
|
||||||
assert response.content != original
|
assert response.content != original
|
||||||
modified_json = json.loads(force_text(response.content))
|
modified_json = json.loads(force_text(response.content))
|
||||||
self.user = self.user.reload()
|
self.user = self.user.reload()
|
||||||
for prop, value in six.iteritems(self.update_data):
|
for prop, value in self.update_data.items():
|
||||||
assert modified_json[prop] == value
|
assert modified_json[prop] == value
|
||||||
assert getattr(self.user, prop) == value
|
assert getattr(self.user, prop) == value
|
||||||
|
|
||||||
|
@ -1175,7 +1174,7 @@ class TestAccountViewSetUpdate(TestCase):
|
||||||
assert response.content != original
|
assert response.content != original
|
||||||
modified_json = json.loads(force_text(response.content))
|
modified_json = json.loads(force_text(response.content))
|
||||||
random_user = random_user.reload()
|
random_user = random_user.reload()
|
||||||
for prop, value in six.iteritems(self.update_data):
|
for prop, value in self.update_data.items():
|
||||||
assert modified_json[prop] == value
|
assert modified_json[prop] == value
|
||||||
assert getattr(random_user, prop) == value
|
assert getattr(random_user, prop) == value
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from base64 import urlsafe_b64encode
|
from base64 import urlsafe_b64encode
|
||||||
|
from urllib.parse import urlencode, urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
@ -10,8 +11,6 @@ from django.utils.encoding import force_text
|
||||||
from django.utils.http import is_safe_url
|
from django.utils.http import is_safe_url
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
import six
|
|
||||||
from six.moves.urllib_parse import urlencode, urlparse
|
|
||||||
|
|
||||||
from olympia.accounts.tasks import primary_email_change_event
|
from olympia.accounts.tasks import primary_email_change_event
|
||||||
from olympia.core.logger import getLogger
|
from olympia.core.logger import getLogger
|
||||||
|
@ -31,7 +30,7 @@ def _is_safe_url(url, request):
|
||||||
|
|
||||||
def fxa_config(request):
|
def fxa_config(request):
|
||||||
config = {camel_case(key): value
|
config = {camel_case(key): value
|
||||||
for key, value in six.iteritems(settings.FXA_CONFIG['default'])
|
for key, value in settings.FXA_CONFIG['default'].items()
|
||||||
if key != 'client_secret'}
|
if key != 'client_secret'}
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
config['email'] = request.user.email
|
config['email'] = request.user.email
|
||||||
|
|
|
@ -14,7 +14,6 @@ from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from corsheaders.conf import conf as corsheaders_conf
|
from corsheaders.conf import conf as corsheaders_conf
|
||||||
|
@ -540,7 +539,7 @@ class ProfileView(APIView):
|
||||||
account_viewset = AccountViewSet(
|
account_viewset = AccountViewSet(
|
||||||
request=request,
|
request=request,
|
||||||
permission_classes=self.permission_classes,
|
permission_classes=self.permission_classes,
|
||||||
kwargs={'pk': six.text_type(self.request.user.pk)})
|
kwargs={'pk': str(self.request.user.pk)})
|
||||||
account_viewset.format_kwarg = self.format_kwarg
|
account_viewset.format_kwarg = self.format_kwarg
|
||||||
return account_viewset.retrieve(request)
|
return account_viewset.retrieve(request)
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,9 @@ from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
import six
|
|
||||||
|
|
||||||
import olympia.core.logger
|
import olympia.core.logger
|
||||||
|
|
||||||
|
@ -296,7 +294,6 @@ class SafeFormatter(string.Formatter):
|
||||||
return jinja2.escape(obj), used_key
|
return jinja2.escape(obj), used_key
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class ActivityLog(ModelBase):
|
class ActivityLog(ModelBase):
|
||||||
TYPES = sorted(
|
TYPES = sorted(
|
||||||
[(value.id, key)
|
[(value.id, key)
|
||||||
|
@ -363,18 +360,16 @@ class ActivityLog(ModelBase):
|
||||||
serialize_me = []
|
serialize_me = []
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, six.string_types):
|
if isinstance(arg, str):
|
||||||
serialize_me.append({'str': arg})
|
serialize_me.append({'str': arg})
|
||||||
elif isinstance(arg, six.integer_types):
|
elif isinstance(arg, int):
|
||||||
serialize_me.append({'int': arg})
|
serialize_me.append({'int': arg})
|
||||||
elif isinstance(arg, tuple):
|
elif isinstance(arg, tuple):
|
||||||
# Instead of passing an addon instance you can pass a tuple:
|
# Instead of passing an addon instance you can pass a tuple:
|
||||||
# (Addon, 3) for Addon with pk=3
|
# (Addon, 3) for Addon with pk=3
|
||||||
serialize_me.append(
|
serialize_me.append(dict(((str(arg[0]._meta), arg[1]),)))
|
||||||
dict(((six.text_type(arg[0]._meta), arg[1]),)))
|
|
||||||
else:
|
else:
|
||||||
serialize_me.append(
|
serialize_me.append(dict(((str(arg._meta), arg.pk),)))
|
||||||
dict(((six.text_type(arg._meta), arg.pk),)))
|
|
||||||
|
|
||||||
self._arguments = json.dumps(serialize_me)
|
self._arguments = json.dumps(serialize_me)
|
||||||
|
|
||||||
|
@ -485,7 +480,7 @@ class ActivityLog(ModelBase):
|
||||||
'file': file_,
|
'file': file_,
|
||||||
'status': status,
|
'status': status,
|
||||||
}
|
}
|
||||||
return self.f(six.text_type(format), *arguments, **kw)
|
return self.f(str(format), *arguments, **kw)
|
||||||
except (AttributeError, KeyError, IndexError):
|
except (AttributeError, KeyError, IndexError):
|
||||||
log.warning('%d contains garbage data' % (self.id or 0))
|
log.warning('%d contains garbage data' % (self.id or 0))
|
||||||
return 'Something magical happened.'
|
return 'Something magical happened.'
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
|
|
||||||
|
@ -103,7 +101,7 @@ class TestActivityLog(TestCase):
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert entries[0].arguments[0] == addon
|
assert entries[0].arguments[0] == addon
|
||||||
for x in ('Delicious Bookmarks', 'was created.'):
|
for x in ('Delicious Bookmarks', 'was created.'):
|
||||||
assert x in six.text_type(entries[0])
|
assert x in str(entries[0])
|
||||||
|
|
||||||
def test_no_user(self):
|
def test_no_user(self):
|
||||||
core.set_user(None)
|
core.set_user(None)
|
||||||
|
@ -133,7 +131,7 @@ class TestActivityLog(TestCase):
|
||||||
ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
|
ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
|
||||||
entries = ActivityLog.objects.for_addons(addon)
|
entries = ActivityLog.objects.for_addons(addon)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert addon.get_url_path() in six.text_type(entries[0])
|
assert addon.get_url_path() in str(entries[0])
|
||||||
|
|
||||||
def test_addon_log_unlisted_addon(self):
|
def test_addon_log_unlisted_addon(self):
|
||||||
addon = Addon.objects.get()
|
addon = Addon.objects.get()
|
||||||
|
@ -145,7 +143,7 @@ class TestActivityLog(TestCase):
|
||||||
ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
|
ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
|
||||||
entries = ActivityLog.objects.for_addons(addon)
|
entries = ActivityLog.objects.for_addons(addon)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert url_path not in six.text_type(entries[0])
|
assert url_path not in str(entries[0])
|
||||||
|
|
||||||
def test_fancy_rendering(self):
|
def test_fancy_rendering(self):
|
||||||
"""HTML for Rating, and Collection."""
|
"""HTML for Rating, and Collection."""
|
||||||
|
@ -192,7 +190,7 @@ class TestActivityLog(TestCase):
|
||||||
def test_output(self):
|
def test_output(self):
|
||||||
ActivityLog.create(amo.LOG.CUSTOM_TEXT, 'hi there')
|
ActivityLog.create(amo.LOG.CUSTOM_TEXT, 'hi there')
|
||||||
entry = ActivityLog.objects.get()
|
entry = ActivityLog.objects.get()
|
||||||
assert six.text_type(entry) == 'hi there'
|
assert str(entry) == 'hi there'
|
||||||
|
|
||||||
def test_user_log(self):
|
def test_user_log(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
|
@ -220,7 +218,7 @@ class TestActivityLog(TestCase):
|
||||||
user=self.request.user)
|
user=self.request.user)
|
||||||
entries = ActivityLog.objects.for_version(version)
|
entries = ActivityLog.objects.for_version(version)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert version.get_url_path() in six.text_type(entries[0])
|
assert version.get_url_path() in str(entries[0])
|
||||||
|
|
||||||
def test_version_log_unlisted_addon(self):
|
def test_version_log_unlisted_addon(self):
|
||||||
version = Version.objects.all()[0]
|
version = Version.objects.all()[0]
|
||||||
|
@ -231,7 +229,7 @@ class TestActivityLog(TestCase):
|
||||||
user=self.request.user)
|
user=self.request.user)
|
||||||
entries = ActivityLog.objects.for_version(version)
|
entries = ActivityLog.objects.for_version(version)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert url_path not in six.text_type(entries[0])
|
assert url_path not in str(entries[0])
|
||||||
|
|
||||||
def test_version_log_transformer(self):
|
def test_version_log_transformer(self):
|
||||||
addon = Addon.objects.get()
|
addon = Addon.objects.get()
|
||||||
|
@ -260,7 +258,7 @@ class TestActivityLog(TestCase):
|
||||||
au = AddonUser(addon=addon, user=self.user)
|
au = AddonUser(addon=addon, user=self.user)
|
||||||
ActivityLog.create(
|
ActivityLog.create(
|
||||||
amo.LOG.CHANGE_USER_WITH_ROLE, au.user,
|
amo.LOG.CHANGE_USER_WITH_ROLE, au.user,
|
||||||
six.text_type(au.get_role_display()), addon)
|
str(au.get_role_display()), addon)
|
||||||
log = ActivityLog.objects.get()
|
log = ActivityLog.objects.get()
|
||||||
|
|
||||||
log_expected = ('Yolo role changed to Owner for <a href="/en-US/'
|
log_expected = ('Yolo role changed to Owner for <a href="/en-US/'
|
||||||
|
@ -287,28 +285,28 @@ class TestActivityLog(TestCase):
|
||||||
amo.LOG.CHANGE_STATUS, addon, amo.STATUS_APPROVED)
|
amo.LOG.CHANGE_STATUS, addon, amo.STATUS_APPROVED)
|
||||||
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
||||||
'Delicious Bookmarks</a> status changed to Approved.')
|
'Delicious Bookmarks</a> status changed to Approved.')
|
||||||
assert six.text_type(log) == expected
|
assert str(log) == expected
|
||||||
|
|
||||||
log.arguments = [amo.STATUS_DISABLED, addon]
|
log.arguments = [amo.STATUS_DISABLED, addon]
|
||||||
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
||||||
'Delicious Bookmarks</a> status changed to '
|
'Delicious Bookmarks</a> status changed to '
|
||||||
'Disabled by Mozilla.')
|
'Disabled by Mozilla.')
|
||||||
assert six.text_type(log) == expected
|
assert str(log) == expected
|
||||||
|
|
||||||
log.arguments = [addon, amo.STATUS_REJECTED]
|
log.arguments = [addon, amo.STATUS_REJECTED]
|
||||||
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
||||||
'Delicious Bookmarks</a> status changed to Rejected.')
|
'Delicious Bookmarks</a> status changed to Rejected.')
|
||||||
assert six.text_type(log) == expected
|
assert str(log) == expected
|
||||||
|
|
||||||
log.arguments = [addon, 666]
|
log.arguments = [addon, 666]
|
||||||
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
||||||
'Delicious Bookmarks</a> status changed to 666.')
|
'Delicious Bookmarks</a> status changed to 666.')
|
||||||
assert six.text_type(log) == expected
|
assert str(log) == expected
|
||||||
|
|
||||||
log.arguments = [addon, 'Some String']
|
log.arguments = [addon, 'Some String']
|
||||||
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
expected = ('<a href="/en-US/firefox/addon/a3615/">'
|
||||||
'Delicious Bookmarks</a> status changed to Some String.')
|
'Delicious Bookmarks</a> status changed to Some String.')
|
||||||
assert six.text_type(log) == expected
|
assert str(log) == expected
|
||||||
|
|
||||||
|
|
||||||
class TestActivityLogCount(TestCase):
|
class TestActivityLogCount(TestCase):
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
|
import io
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.activity.models import ActivityLog, ActivityLogToken
|
from olympia.activity.models import ActivityLog, ActivityLogToken
|
||||||
from olympia.activity.tests.test_serializers import LogMixin
|
from olympia.activity.tests.test_serializers import LogMixin
|
||||||
|
@ -276,7 +275,7 @@ class TestReviewNotesViewSetCreate(TestCase):
|
||||||
rdata = response.data
|
rdata = response.data
|
||||||
assert reply.pk == rdata['id']
|
assert reply.pk == rdata['id']
|
||||||
assert (
|
assert (
|
||||||
six.text_type(reply.details['comments']) == rdata['comments'] ==
|
str(reply.details['comments']) == rdata['comments'] ==
|
||||||
u'comménty McCómm€nt')
|
u'comménty McCómm€nt')
|
||||||
assert reply.user == self.user
|
assert reply.user == self.user
|
||||||
assert reply.user.name == rdata['user']['name'] == self.user.name
|
assert reply.user.name == rdata['user']['name'] == self.user.name
|
||||||
|
@ -302,7 +301,7 @@ class TestReviewNotesViewSetCreate(TestCase):
|
||||||
rdata = response.data
|
rdata = response.data
|
||||||
assert reply.pk == rdata['id']
|
assert reply.pk == rdata['id']
|
||||||
assert (
|
assert (
|
||||||
six.text_type(reply.details['comments']) == rdata['comments'] ==
|
str(reply.details['comments']) == rdata['comments'] ==
|
||||||
u'comménty McCómm€nt')
|
u'comménty McCómm€nt')
|
||||||
assert reply.user == self.user
|
assert reply.user == self.user
|
||||||
assert reply.user.name == rdata['user']['name'] == self.user.name
|
assert reply.user.name == rdata['user']['name'] == self.user.name
|
||||||
|
@ -396,7 +395,7 @@ class TestEmailApi(TestCase):
|
||||||
req.META['REMOTE_ADDR'] = '10.10.10.10'
|
req.META['REMOTE_ADDR'] = '10.10.10.10'
|
||||||
req.META['CONTENT_LENGTH'] = len(datastr)
|
req.META['CONTENT_LENGTH'] = len(datastr)
|
||||||
req.META['CONTENT_TYPE'] = 'application/json'
|
req.META['CONTENT_TYPE'] = 'application/json'
|
||||||
req._stream = six.BytesIO(datastr)
|
req._stream = io.BytesIO(datastr)
|
||||||
return req
|
return req
|
||||||
|
|
||||||
def get_validation_request(self, data):
|
def get_validation_request(self, data):
|
||||||
|
|
|
@ -2,7 +2,7 @@ import re
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from email.utils import formataddr
|
from email.utils import formataddr
|
||||||
from six.moves.html_parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from six.moves.urllib_parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django import http, forms
|
from django import http, forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
|
@ -9,6 +9,7 @@ import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
@ -16,16 +17,13 @@ from django.db import IntegrityError, models, transaction
|
||||||
from django.db.models import F, Max, Q, signals as dbsignals
|
from django.db.models import F, Max, Q, signals as dbsignals
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
from django.utils.encoding import force_text
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import trans_real, ugettext_lazy as _
|
from django.utils.translation import trans_real, ugettext_lazy as _
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from django_extensions.db.fields.json import JSONField
|
from django_extensions.db.fields.json import JSONField
|
||||||
from django_statsd.clients import statsd
|
from django_statsd.clients import statsd
|
||||||
from jinja2.filters import do_dictsort
|
from jinja2.filters import do_dictsort
|
||||||
from six.moves.urllib_parse import urlsplit
|
|
||||||
|
|
||||||
import olympia.core.logger
|
import olympia.core.logger
|
||||||
|
|
||||||
|
@ -154,7 +152,7 @@ def clean_slug(instance, slug_field='slug'):
|
||||||
class AddonQuerySet(BaseQuerySet):
|
class AddonQuerySet(BaseQuerySet):
|
||||||
def id_or_slug(self, val):
|
def id_or_slug(self, val):
|
||||||
"""Get add-ons by id or slug."""
|
"""Get add-ons by id or slug."""
|
||||||
if isinstance(val, six.string_types) and not val.isdigit():
|
if isinstance(val, str) and not val.isdigit():
|
||||||
return self.filter(slug=val)
|
return self.filter(slug=val)
|
||||||
return self.filter(id=val)
|
return self.filter(id=val)
|
||||||
|
|
||||||
|
@ -339,7 +337,6 @@ class AddonManager(ManagerBase):
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Addon(OnChangeMixin, ModelBase):
|
class Addon(OnChangeMixin, ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
STATUS_CHOICES = amo.STATUS_CHOICES_ADDON
|
STATUS_CHOICES = amo.STATUS_CHOICES_ADDON
|
||||||
|
@ -574,7 +571,7 @@ class Addon(OnChangeMixin, ModelBase):
|
||||||
self._ratings.all().delete()
|
self._ratings.all().delete()
|
||||||
# The last parameter is needed to automagically create an AddonLog.
|
# The last parameter is needed to automagically create an AddonLog.
|
||||||
activity.log_create(amo.LOG.DELETE_ADDON, self.pk,
|
activity.log_create(amo.LOG.DELETE_ADDON, self.pk,
|
||||||
six.text_type(self.guid), self)
|
str(self.guid), self)
|
||||||
self.update(status=amo.STATUS_DELETED, slug=None,
|
self.update(status=amo.STATUS_DELETED, slug=None,
|
||||||
_current_version=None, modified=datetime.now())
|
_current_version=None, modified=datetime.now())
|
||||||
models.signals.post_delete.send(sender=Addon, instance=self)
|
models.signals.post_delete.send(sender=Addon, instance=self)
|
||||||
|
@ -856,7 +853,7 @@ class Addon(OnChangeMixin, ModelBase):
|
||||||
# as File's) when deleting a version. If so, we should avoid putting
|
# as File's) when deleting a version. If so, we should avoid putting
|
||||||
# that version-being-deleted in any fields.
|
# that version-being-deleted in any fields.
|
||||||
if ignore is not None:
|
if ignore is not None:
|
||||||
updated = {k: v for k, v in six.iteritems(updated) if v != ignore}
|
updated = {k: v for k, v in updated.items() if v != ignore}
|
||||||
|
|
||||||
if updated:
|
if updated:
|
||||||
diff = [self._current_version, new_current_version]
|
diff = [self._current_version, new_current_version]
|
||||||
|
@ -1600,7 +1597,6 @@ class AddonReviewerFlags(ModelBase):
|
||||||
notified_about_expiring_info_request = models.BooleanField(default=False)
|
notified_about_expiring_info_request = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Persona(models.Model):
|
class Persona(models.Model):
|
||||||
"""Personas-specific additions to the add-on model."""
|
"""Personas-specific additions to the add-on model."""
|
||||||
STATUS_CHOICES = amo.STATUS_CHOICES_PERSONA
|
STATUS_CHOICES = amo.STATUS_CHOICES_PERSONA
|
||||||
|
@ -1632,7 +1628,7 @@ class Persona(models.Model):
|
||||||
db_table = 'personas'
|
db_table = 'personas'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self.addon.name)
|
return str(self.addon.name)
|
||||||
|
|
||||||
def is_new(self):
|
def is_new(self):
|
||||||
return self.persona_id == 0
|
return self.persona_id == 0
|
||||||
|
@ -1741,15 +1737,15 @@ class Persona(models.Model):
|
||||||
|
|
||||||
addon = self.addon
|
addon = self.addon
|
||||||
return {
|
return {
|
||||||
'id': six.text_type(self.addon.id), # Personas dislikes ints
|
'id': str(self.addon.id), # Personas dislikes ints
|
||||||
'name': six.text_type(addon.name),
|
'name': str(addon.name),
|
||||||
'accentcolor': hexcolor(self.accentcolor),
|
'accentcolor': hexcolor(self.accentcolor),
|
||||||
'textcolor': hexcolor(self.textcolor),
|
'textcolor': hexcolor(self.textcolor),
|
||||||
'category': (six.text_type(addon.all_categories[0].name) if
|
'category': (str(addon.all_categories[0].name) if
|
||||||
addon.all_categories else ''),
|
addon.all_categories else ''),
|
||||||
# TODO: Change this to be `addons_users.user.display_name`.
|
# TODO: Change this to be `addons_users.user.display_name`.
|
||||||
'author': self.display_username,
|
'author': self.display_username,
|
||||||
'description': (six.text_type(addon.description)
|
'description': (str(addon.description)
|
||||||
if addon.description is not None
|
if addon.description is not None
|
||||||
else addon.description),
|
else addon.description),
|
||||||
'header': self.header_url,
|
'header': self.header_url,
|
||||||
|
@ -1845,7 +1841,6 @@ def watch_addon_user(old_attr=None, new_attr=None, instance=None, sender=None,
|
||||||
update_search_index(sender=sender, instance=instance.addon, **kwargs)
|
update_search_index(sender=sender, instance=instance.addon, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class AddonApprovalsCounter(ModelBase):
|
class AddonApprovalsCounter(ModelBase):
|
||||||
"""Model holding a counter of the number of times a listed version
|
"""Model holding a counter of the number of times a listed version
|
||||||
belonging to an add-on has been approved by a human. Reset everytime a
|
belonging to an add-on has been approved by a human. Reset everytime a
|
||||||
|
@ -1864,8 +1859,7 @@ class AddonApprovalsCounter(ModelBase):
|
||||||
last_content_review = models.DateTimeField(null=True)
|
last_content_review = models.DateTimeField(null=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return u'%s: %d' % (
|
return u'%s: %d' % (str(self.pk), self.counter) if self.pk else u''
|
||||||
six.text_type(self.pk), self.counter) if self.pk else u''
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def increment_for_addon(cls, addon):
|
def increment_for_addon(cls, addon):
|
||||||
|
@ -1909,7 +1903,6 @@ class AddonApprovalsCounter(ModelBase):
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class DeniedGuid(ModelBase):
|
class DeniedGuid(ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
guid = models.CharField(max_length=255, unique=True)
|
guid = models.CharField(max_length=255, unique=True)
|
||||||
|
@ -1922,7 +1915,6 @@ class DeniedGuid(ModelBase):
|
||||||
return self.guid
|
return self.guid
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Category(OnChangeMixin, ModelBase):
|
class Category(OnChangeMixin, ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
slug = SlugField(max_length=50, help_text='Used in Category URLs.')
|
slug = SlugField(max_length=50, help_text='Used in Category URLs.')
|
||||||
|
@ -1950,10 +1942,10 @@ class Category(OnChangeMixin, ModelBase):
|
||||||
# We can't find the category in the constants dict. This shouldn't
|
# We can't find the category in the constants dict. This shouldn't
|
||||||
# happen, but just in case handle it by returning an empty string.
|
# happen, but just in case handle it by returning an empty string.
|
||||||
value = ''
|
value = ''
|
||||||
return six.text_type(value)
|
return str(value)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self.name)
|
return str(self.name)
|
||||||
|
|
||||||
def get_url_path(self):
|
def get_url_path(self):
|
||||||
try:
|
try:
|
||||||
|
@ -2024,7 +2016,6 @@ class AppSupport(ModelBase):
|
||||||
unique_together = ('addon', 'app')
|
unique_together = ('addon', 'app')
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class DeniedSlug(ModelBase):
|
class DeniedSlug(ModelBase):
|
||||||
name = models.CharField(max_length=255, unique=True, default='')
|
name = models.CharField(max_length=255, unique=True, default='')
|
||||||
|
|
||||||
|
@ -2039,7 +2030,6 @@ class DeniedSlug(ModelBase):
|
||||||
return slug.isdigit() or cls.objects.filter(name=slug).exists()
|
return slug.isdigit() or cls.objects.filter(name=slug).exists()
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class FrozenAddon(models.Model):
|
class FrozenAddon(models.Model):
|
||||||
"""Add-ons in this table never get a hotness score."""
|
"""Add-ons in this table never get a hotness score."""
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
|
@ -2059,7 +2049,6 @@ def freezer(sender, instance, **kw):
|
||||||
Addon.objects.get(id=instance.addon_id).update(hotness=0)
|
Addon.objects.get(id=instance.addon_id).update(hotness=0)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class CompatOverride(ModelBase):
|
class CompatOverride(ModelBase):
|
||||||
"""Helps manage compat info for add-ons not hosted on AMO."""
|
"""Helps manage compat info for add-ons not hosted on AMO."""
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
|
@ -2082,7 +2071,7 @@ class CompatOverride(ModelBase):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.addon:
|
if self.addon:
|
||||||
return six.text_type(self.addon)
|
return str(self.addon)
|
||||||
elif self.name:
|
elif self.name:
|
||||||
return '%s (%s)' % (self.name, self.guid)
|
return '%s (%s)' % (self.name, self.guid)
|
||||||
else:
|
else:
|
||||||
|
@ -2160,7 +2149,6 @@ class CompatOverrideRange(ModelBase):
|
||||||
return {0: 'compatible', 1: 'incompatible'}[self.type]
|
return {0: 'compatible', 1: 'incompatible'}[self.type]
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class IncompatibleVersions(ModelBase):
|
class IncompatibleVersions(ModelBase):
|
||||||
"""
|
"""
|
||||||
Denormalized table to join against for fast compat override filtering.
|
Denormalized table to join against for fast compat override filtering.
|
||||||
|
|
|
@ -2,8 +2,6 @@ import re
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework import exceptions, serializers
|
from rest_framework import exceptions, serializers
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
@ -125,11 +123,11 @@ class LicenseSerializer(serializers.ModelSerializer):
|
||||||
request = self.context.get('request', None)
|
request = self.context.get('request', None)
|
||||||
if request and request.method == 'GET' and 'lang' in request.GET:
|
if request and request.method == 'GET' and 'lang' in request.GET:
|
||||||
# A single lang requested so return a flat string
|
# A single lang requested so return a flat string
|
||||||
return six.text_type(license_constant.name)
|
return str(license_constant.name)
|
||||||
else:
|
else:
|
||||||
# Otherwise mock the dict with the default lang.
|
# Otherwise mock the dict with the default lang.
|
||||||
lang = getattr(request, 'LANG', None) or settings.LANGUAGE_CODE
|
lang = getattr(request, 'LANG', None) or settings.LANGUAGE_CODE
|
||||||
return {lang: six.text_type(license_constant.name)}
|
return {lang: str(license_constant.name)}
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
data = super(LicenseSerializer, self).to_representation(instance)
|
data = super(LicenseSerializer, self).to_representation(instance)
|
||||||
|
@ -234,7 +232,7 @@ class CurrentVersionSerializer(SimpleVersionSerializer):
|
||||||
application = value[0]
|
application = value[0]
|
||||||
appversions = dict(zip(('min', 'max'), value[1:]))
|
appversions = dict(zip(('min', 'max'), value[1:]))
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise exceptions.ParseError(six.text_type(exc))
|
raise exceptions.ParseError(str(exc))
|
||||||
|
|
||||||
version_qs = Version.objects.latest_public_compatible_with(
|
version_qs = Version.objects.latest_public_compatible_with(
|
||||||
application, appversions).filter(addon=addon)
|
application, appversions).filter(addon=addon)
|
||||||
|
@ -375,7 +373,7 @@ class AddonSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
def outgoingify(self, data):
|
def outgoingify(self, data):
|
||||||
if data:
|
if data:
|
||||||
if isinstance(data, six.string_types):
|
if isinstance(data, str):
|
||||||
return get_outgoing_url(data)
|
return get_outgoing_url(data)
|
||||||
elif isinstance(data, dict):
|
elif isinstance(data, dict):
|
||||||
return {key: get_outgoing_url(value) if value else None
|
return {key: get_outgoing_url(value) if value else None
|
||||||
|
@ -726,7 +724,7 @@ class ReplacementAddonSerializer(serializers.ModelSerializer):
|
||||||
def _get_collection_guids(self, user_id, collection_slug):
|
def _get_collection_guids(self, user_id, collection_slug):
|
||||||
try:
|
try:
|
||||||
get_args = {'slug': collection_slug, 'listed': True}
|
get_args = {'slug': collection_slug, 'listed': True}
|
||||||
if isinstance(user_id, six.string_types) and not user_id.isdigit():
|
if isinstance(user_id, str) and not user_id.isdigit():
|
||||||
get_args.update(**{'author__username': user_id})
|
get_args.update(**{'author__username': user_id})
|
||||||
else:
|
else:
|
||||||
get_args.update(**{'author': user_id})
|
get_args.update(**{'author': user_id})
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
from django import http
|
from django import http
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from urllib.parse import quote
|
||||||
from six.moves.urllib_parse import quote
|
|
||||||
|
|
||||||
from olympia.addons import decorators as dec
|
from olympia.addons import decorators as dec
|
||||||
from olympia.addons.models import Addon
|
from olympia.addons.models import Addon
|
||||||
|
|
|
@ -4,6 +4,7 @@ import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -11,9 +12,6 @@ from django.core import mail
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import Mock, patch
|
|
||||||
|
|
||||||
from olympia import amo, core
|
from olympia import amo, core
|
||||||
from olympia.activity.models import ActivityLog, AddonLog
|
from olympia.activity.models import ActivityLog, AddonLog
|
||||||
|
@ -2112,12 +2110,12 @@ class TestPersonaModel(TestCase):
|
||||||
id_ = str(self.persona.addon.id)
|
id_ = str(self.persona.addon.id)
|
||||||
|
|
||||||
assert data['id'] == id_
|
assert data['id'] == id_
|
||||||
assert data['name'] == six.text_type(self.persona.addon.name)
|
assert data['name'] == str(self.persona.addon.name)
|
||||||
assert data['accentcolor'] == '#8d8d97'
|
assert data['accentcolor'] == '#8d8d97'
|
||||||
assert data['textcolor'] == '#ffffff'
|
assert data['textcolor'] == '#ffffff'
|
||||||
assert data['category'] == 'Abstract'
|
assert data['category'] == 'Abstract'
|
||||||
assert data['author'] == 'persona_author ®'
|
assert data['author'] == 'persona_author ®'
|
||||||
assert data['description'] == six.text_type(self.addon.description)
|
assert data['description'] == str(self.addon.description)
|
||||||
|
|
||||||
assert data['headerURL'].startswith(
|
assert data['headerURL'].startswith(
|
||||||
'%s%s/header.png?' % (user_media_url('addons'), id_))
|
'%s%s/header.png?' % (user_media_url('addons'), id_))
|
||||||
|
@ -2151,12 +2149,12 @@ class TestPersonaModel(TestCase):
|
||||||
id_ = str(self.persona.addon.id)
|
id_ = str(self.persona.addon.id)
|
||||||
|
|
||||||
assert data['id'] == id_
|
assert data['id'] == id_
|
||||||
assert data['name'] == six.text_type(self.persona.addon.name)
|
assert data['name'] == str(self.persona.addon.name)
|
||||||
assert data['accentcolor'] == '#8d8d97'
|
assert data['accentcolor'] == '#8d8d97'
|
||||||
assert data['textcolor'] == '#ffffff'
|
assert data['textcolor'] == '#ffffff'
|
||||||
assert data['category'] == 'Abstract'
|
assert data['category'] == 'Abstract'
|
||||||
assert data['author'] == 'persona_author ®'
|
assert data['author'] == 'persona_author ®'
|
||||||
assert data['description'] == six.text_type(self.addon.description)
|
assert data['description'] == str(self.addon.description)
|
||||||
|
|
||||||
assert data['headerURL'].startswith(
|
assert data['headerURL'].startswith(
|
||||||
'%s%s/header.png?' % (user_media_url('addons'), id_))
|
'%s%s/header.png?' % (user_media_url('addons'), id_))
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.translation import override
|
from django.utils.translation import override
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework.test import APIRequestFactory
|
from rest_framework.test import APIRequestFactory
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
@ -221,9 +219,7 @@ class AddonSerializerOutputTestMixin(object):
|
||||||
assert result['guid'] == self.addon.guid
|
assert result['guid'] == self.addon.guid
|
||||||
assert result['has_eula'] is False
|
assert result['has_eula'] is False
|
||||||
assert result['has_privacy_policy'] is False
|
assert result['has_privacy_policy'] is False
|
||||||
assert result['homepage'] == {
|
assert result['homepage'] == {'en-US': str(self.addon.homepage)}
|
||||||
'en-US': six.text_type(self.addon.homepage),
|
|
||||||
}
|
|
||||||
assert result['icon_url'] == absolutify(self.addon.get_icon_url(64))
|
assert result['icon_url'] == absolutify(self.addon.get_icon_url(64))
|
||||||
assert result['icons'] == {
|
assert result['icons'] == {
|
||||||
'32': absolutify(self.addon.get_icon_url(32)),
|
'32': absolutify(self.addon.get_icon_url(32)),
|
||||||
|
@ -283,9 +279,7 @@ class AddonSerializerOutputTestMixin(object):
|
||||||
assert result['status'] == 'public'
|
assert result['status'] == 'public'
|
||||||
assert result['summary'] == {'en-US': self.addon.summary}
|
assert result['summary'] == {'en-US': self.addon.summary}
|
||||||
assert result['support_email'] == {'en-US': self.addon.support_email}
|
assert result['support_email'] == {'en-US': self.addon.support_email}
|
||||||
assert result['support_url'] == {
|
assert result['support_url'] == {'en-US': str(self.addon.support_url)}
|
||||||
'en-US': six.text_type(self.addon.support_url),
|
|
||||||
}
|
|
||||||
assert set(result['tags']) == {'some_tag', 'some_other_tag'}
|
assert set(result['tags']) == {'some_tag', 'some_other_tag'}
|
||||||
assert result['type'] == 'extension'
|
assert result['type'] == 'extension'
|
||||||
assert result['url'] == self.addon.get_absolute_url()
|
assert result['url'] == self.addon.get_absolute_url()
|
||||||
|
@ -301,12 +295,12 @@ class AddonSerializerOutputTestMixin(object):
|
||||||
self.request = APIRequestFactory().get('/', {'wrap_outgoing_links': 1})
|
self.request = APIRequestFactory().get('/', {'wrap_outgoing_links': 1})
|
||||||
result = self.serialize()
|
result = self.serialize()
|
||||||
assert result['contributions_url'] == (
|
assert result['contributions_url'] == (
|
||||||
get_outgoing_url(six.text_type(self.addon.contributions)))
|
get_outgoing_url(str(self.addon.contributions)))
|
||||||
assert result['homepage'] == {
|
assert result['homepage'] == {
|
||||||
'en-US': get_outgoing_url(six.text_type(self.addon.homepage)),
|
'en-US': get_outgoing_url(str(self.addon.homepage)),
|
||||||
}
|
}
|
||||||
assert result['support_url'] == {
|
assert result['support_url'] == {
|
||||||
'en-US': get_outgoing_url(six.text_type(self.addon.support_url)),
|
'en-US': get_outgoing_url(str(self.addon.support_url)),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try a single translation.
|
# Try a single translation.
|
||||||
|
@ -314,24 +308,24 @@ class AddonSerializerOutputTestMixin(object):
|
||||||
'lang': 'en-US', 'wrap_outgoing_links': 1})
|
'lang': 'en-US', 'wrap_outgoing_links': 1})
|
||||||
result = self.serialize()
|
result = self.serialize()
|
||||||
assert result['contributions_url'] == (
|
assert result['contributions_url'] == (
|
||||||
get_outgoing_url(six.text_type(self.addon.contributions)))
|
get_outgoing_url(str(self.addon.contributions)))
|
||||||
assert result['homepage'] == {
|
assert result['homepage'] == {
|
||||||
'en-US': get_outgoing_url(six.text_type(self.addon.homepage)),
|
'en-US': get_outgoing_url(str(self.addon.homepage)),
|
||||||
}
|
}
|
||||||
assert result['support_url'] == {
|
assert result['support_url'] == {
|
||||||
'en-US': get_outgoing_url(six.text_type(self.addon.support_url)),
|
'en-US': get_outgoing_url(str(self.addon.support_url)),
|
||||||
}
|
}
|
||||||
# And again, but with v3 style flat strings
|
# And again, but with v3 style flat strings
|
||||||
gates = {None: ('l10n_flat_input_output',)}
|
gates = {None: ('l10n_flat_input_output',)}
|
||||||
with override_settings(DRF_API_GATES=gates):
|
with override_settings(DRF_API_GATES=gates):
|
||||||
result = self.serialize()
|
result = self.serialize()
|
||||||
assert result['contributions_url'] == (
|
assert result['contributions_url'] == (
|
||||||
get_outgoing_url(six.text_type(self.addon.contributions)))
|
get_outgoing_url(str(self.addon.contributions)))
|
||||||
assert result['homepage'] == (
|
assert result['homepage'] == (
|
||||||
get_outgoing_url(six.text_type(self.addon.homepage))
|
get_outgoing_url(str(self.addon.homepage))
|
||||||
)
|
)
|
||||||
assert result['support_url'] == (
|
assert result['support_url'] == (
|
||||||
get_outgoing_url(six.text_type(self.addon.support_url))
|
get_outgoing_url(str(self.addon.support_url))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Try with empty strings/None. Annoyingly, contribution model field
|
# Try with empty strings/None. Annoyingly, contribution model field
|
||||||
|
@ -1016,7 +1010,7 @@ class TestVersionSerializerOutput(TestCase):
|
||||||
# A request with no ?lang gets you the site default l10n in a dict to
|
# A request with no ?lang gets you the site default l10n in a dict to
|
||||||
# match how non-constant values are returned.
|
# match how non-constant values are returned.
|
||||||
assert result['name'] == {
|
assert result['name'] == {
|
||||||
'en-US': six.text_type(LICENSES_BY_BUILTIN[18].name)}
|
'en-US': str(LICENSES_BY_BUILTIN[18].name)}
|
||||||
|
|
||||||
accept_request = APIRequestFactory().get('/')
|
accept_request = APIRequestFactory().get('/')
|
||||||
accept_request.LANG = 'de'
|
accept_request.LANG = 'de'
|
||||||
|
@ -1024,13 +1018,13 @@ class TestVersionSerializerOutput(TestCase):
|
||||||
context={'request': accept_request}).to_representation(license)
|
context={'request': accept_request}).to_representation(license)
|
||||||
# An Accept-Language should result in a different default though.
|
# An Accept-Language should result in a different default though.
|
||||||
assert result['name'] == {
|
assert result['name'] == {
|
||||||
'de': six.text_type(LICENSES_BY_BUILTIN[18].name)}
|
'de': str(LICENSES_BY_BUILTIN[18].name)}
|
||||||
|
|
||||||
# But a requested lang returns a flat string
|
# But a requested lang returns a flat string
|
||||||
lang_request = APIRequestFactory().get('/?lang=fr')
|
lang_request = APIRequestFactory().get('/?lang=fr')
|
||||||
result = LicenseSerializer(
|
result = LicenseSerializer(
|
||||||
context={'request': lang_request}).to_representation(license)
|
context={'request': lang_request}).to_representation(license)
|
||||||
assert result['name'] == six.text_type(LICENSES_BY_BUILTIN[18].name)
|
assert result['name'] == str(LICENSES_BY_BUILTIN[18].name)
|
||||||
|
|
||||||
def test_file_webext_permissions(self):
|
def test_file_webext_permissions(self):
|
||||||
self.version = addon_factory().current_version
|
self.version = addon_factory().current_version
|
||||||
|
@ -1200,7 +1194,7 @@ class TestESAddonAutoCompleteSerializer(ESTestCase):
|
||||||
{'id', 'name', 'icon_url', 'is_recommended', 'type', 'url'}
|
{'id', 'name', 'icon_url', 'is_recommended', 'type', 'url'}
|
||||||
)
|
)
|
||||||
assert result['id'] == self.addon.pk
|
assert result['id'] == self.addon.pk
|
||||||
assert result['name'] == {'en-US': six.text_type(self.addon.name)}
|
assert result['name'] == {'en-US': str(self.addon.name)}
|
||||||
assert result['icon_url'] == absolutify(self.addon.get_icon_url(64))
|
assert result['icon_url'] == absolutify(self.addon.get_icon_url(64))
|
||||||
assert result['is_recommended'] == self.addon.is_recommended is False
|
assert result['is_recommended'] == self.addon.is_recommended is False
|
||||||
assert result['type'] == 'extension'
|
assert result['type'] == 'extension'
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
|
import io
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
import six
|
|
||||||
from six import StringIO
|
|
||||||
from six.moves.urllib_parse import urlencode
|
|
||||||
|
|
||||||
from services import theme_update
|
from services import theme_update
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
@ -23,7 +22,7 @@ class TestWSGIApplication(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestWSGIApplication, self).setUp()
|
super(TestWSGIApplication, self).setUp()
|
||||||
self.environ = {'wsgi.input': StringIO()}
|
self.environ = {'wsgi.input': io.StringIO()}
|
||||||
self.start_response = mock.Mock()
|
self.start_response = mock.Mock()
|
||||||
self.urls = {
|
self.urls = {
|
||||||
'/themes/update-check/5': ['en-US', 5, None],
|
'/themes/update-check/5': ['en-US', 5, None],
|
||||||
|
@ -38,7 +37,7 @@ class TestWSGIApplication(TestCase):
|
||||||
MigratedUpdate_mock.return_value.is_migrated = False
|
MigratedUpdate_mock.return_value.is_migrated = False
|
||||||
LWThemeUpdate_mock.return_value.get_json.return_value = u'{"fo": "bá"}'
|
LWThemeUpdate_mock.return_value.get_json.return_value = u'{"fo": "bá"}'
|
||||||
# From AMO we consume the ID as the `addon_id`.
|
# From AMO we consume the ID as the `addon_id`.
|
||||||
for path_info, call_args in six.iteritems(self.urls):
|
for path_info, call_args in self.urls.items():
|
||||||
environ = dict(self.environ, PATH_INFO=path_info)
|
environ = dict(self.environ, PATH_INFO=path_info)
|
||||||
response = theme_update.application(environ, self.start_response)
|
response = theme_update.application(environ, self.start_response)
|
||||||
# wsgi expects a bytestring, rather than unicode response.
|
# wsgi expects a bytestring, rather than unicode response.
|
||||||
|
@ -49,7 +48,7 @@ class TestWSGIApplication(TestCase):
|
||||||
# From getpersonas.com we append `?src=gp` so we know to consume
|
# From getpersonas.com we append `?src=gp` so we know to consume
|
||||||
# the ID as the `persona_id`.
|
# the ID as the `persona_id`.
|
||||||
self.environ['QUERY_STRING'] = 'src=gp'
|
self.environ['QUERY_STRING'] = 'src=gp'
|
||||||
for path_info, call_args in six.iteritems(self.urls):
|
for path_info, call_args in self.urls.items():
|
||||||
environ = dict(self.environ, PATH_INFO=path_info)
|
environ = dict(self.environ, PATH_INFO=path_info)
|
||||||
theme_update.application(environ, self.start_response)
|
theme_update.application(environ, self.start_response)
|
||||||
call_args[2] = 'src=gp'
|
call_args[2] = 'src=gp'
|
||||||
|
@ -66,7 +65,7 @@ class TestWSGIApplication(TestCase):
|
||||||
MigratedUpdate_mock.return_value.get_json.return_value = (
|
MigratedUpdate_mock.return_value.get_json.return_value = (
|
||||||
u'{"foó": "ba"}')
|
u'{"foó": "ba"}')
|
||||||
# From AMO we consume the ID as the `addon_id`.
|
# From AMO we consume the ID as the `addon_id`.
|
||||||
for path_info, call_args in six.iteritems(self.urls):
|
for path_info, call_args in self.urls.items():
|
||||||
environ = dict(self.environ, PATH_INFO=path_info)
|
environ = dict(self.environ, PATH_INFO=path_info)
|
||||||
response = theme_update.application(environ, self.start_response)
|
response = theme_update.application(environ, self.start_response)
|
||||||
# wsgi expects a bytestring, rather than unicode response.
|
# wsgi expects a bytestring, rather than unicode response.
|
||||||
|
@ -78,7 +77,7 @@ class TestWSGIApplication(TestCase):
|
||||||
# From getpersonas.com we append `?src=gp` so we know to consume
|
# From getpersonas.com we append `?src=gp` so we know to consume
|
||||||
# the ID as the `persona_id`.
|
# the ID as the `persona_id`.
|
||||||
self.environ['QUERY_STRING'] = 'src=gp'
|
self.environ['QUERY_STRING'] = 'src=gp'
|
||||||
for path_info, call_args in six.iteritems(self.urls):
|
for path_info, call_args in self.urls.items():
|
||||||
environ = dict(self.environ, PATH_INFO=path_info)
|
environ = dict(self.environ, PATH_INFO=path_info)
|
||||||
theme_update.application(environ, self.start_response)
|
theme_update.application(environ, self.start_response)
|
||||||
call_args[2] = 'src=gp'
|
call_args[2] = 'src=gp'
|
||||||
|
@ -110,7 +109,7 @@ class TestWSGIApplication(TestCase):
|
||||||
def test_404_for_migrated_but_updates_disabled(
|
def test_404_for_migrated_but_updates_disabled(
|
||||||
self, LWThemeUpdate_mock, MigratedUpdate_mock):
|
self, LWThemeUpdate_mock, MigratedUpdate_mock):
|
||||||
MigratedUpdate_mock.return_value.is_migrated = True
|
MigratedUpdate_mock.return_value.is_migrated = True
|
||||||
for path_info, call_args in six.iteritems(self.urls):
|
for path_info, call_args in self.urls.items():
|
||||||
environ = dict(self.environ, PATH_INFO=path_info)
|
environ = dict(self.environ, PATH_INFO=path_info)
|
||||||
theme_update.application(environ, self.start_response)
|
theme_update.application(environ, self.start_response)
|
||||||
assert not LWThemeUpdate_mock.called
|
assert not LWThemeUpdate_mock.called
|
||||||
|
@ -142,7 +141,7 @@ class TestThemeUpdate(TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
def check_good(self, data):
|
def check_good(self, data):
|
||||||
for k, v in six.iteritems(self.good):
|
for k, v in self.good.items():
|
||||||
got = data[k]
|
got = data[k]
|
||||||
if k.endswith('URL'):
|
if k.endswith('URL'):
|
||||||
if k in ('detailURL', 'updateURL'):
|
if k in ('detailURL', 'updateURL'):
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.encoding import force_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils.http import urlsafe_base64_encode, urlunquote
|
from django.utils.http import urlsafe_base64_encode, urlunquote
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from elasticsearch import Elasticsearch
|
from elasticsearch import Elasticsearch
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
@ -1782,7 +1782,7 @@ class TestAddonSearchView(ESTestCase):
|
||||||
# Exclude addon1 and addon2 by pk.
|
# Exclude addon1 and addon2 by pk.
|
||||||
data = self.perform_search(
|
data = self.perform_search(
|
||||||
self.url, {'exclude_addons': u','.join(
|
self.url, {'exclude_addons': u','.join(
|
||||||
map(six.text_type, (addon2.pk, addon1.pk)))})
|
map(str, (addon2.pk, addon1.pk)))})
|
||||||
|
|
||||||
assert len(data['results']) == 1
|
assert len(data['results']) == 1
|
||||||
assert data['count'] == 1
|
assert data['count'] == 1
|
||||||
|
@ -1791,7 +1791,7 @@ class TestAddonSearchView(ESTestCase):
|
||||||
# Exclude addon1 by pk and addon3 by slug.
|
# Exclude addon1 by pk and addon3 by slug.
|
||||||
data = self.perform_search(
|
data = self.perform_search(
|
||||||
self.url, {'exclude_addons': u','.join(
|
self.url, {'exclude_addons': u','.join(
|
||||||
(six.text_type(addon1.pk), addon3.slug))})
|
(str(addon1.pk), addon3.slug))})
|
||||||
|
|
||||||
assert len(data['results']) == 1
|
assert len(data['results']) == 1
|
||||||
assert data['count'] == 1
|
assert data['count'] == 1
|
||||||
|
|
|
@ -12,7 +12,6 @@ from django.db.models import Q
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from django_statsd.clients import statsd
|
from django_statsd.clients import statsd
|
||||||
|
@ -201,11 +200,10 @@ def build_static_theme_xpi_from_lwt(lwt, upload_zip):
|
||||||
else amo.THEME_FRAME_COLOR_DEFAULT)
|
else amo.THEME_FRAME_COLOR_DEFAULT)
|
||||||
textcolor = '#%s' % (lwt.persona.textcolor or '000')
|
textcolor = '#%s' % (lwt.persona.textcolor or '000')
|
||||||
|
|
||||||
lwt_header = MULTIPLE_STOPS_REGEX.sub(
|
lwt_header = MULTIPLE_STOPS_REGEX.sub(u'.', str(lwt.persona.header))
|
||||||
u'.', six.text_type(lwt.persona.header))
|
|
||||||
manifest = {
|
manifest = {
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": six.text_type(lwt.name) or six.text_type(lwt.slug),
|
"name": str(lwt.name) or str(lwt.slug),
|
||||||
"version": '1.0',
|
"version": '1.0',
|
||||||
"theme": {
|
"theme": {
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -218,7 +216,7 @@ def build_static_theme_xpi_from_lwt(lwt, upload_zip):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lwt.description:
|
if lwt.description:
|
||||||
manifest['description'] = six.text_type(lwt.description)
|
manifest['description'] = str(lwt.description)
|
||||||
|
|
||||||
# build zip with manifest and background file
|
# build zip with manifest and background file
|
||||||
with zipfile.ZipFile(upload_zip, 'w', zipfile.ZIP_DEFLATED) as dest:
|
with zipfile.ZipFile(upload_zip, 'w', zipfile.ZIP_DEFLATED) as dest:
|
||||||
|
@ -292,7 +290,7 @@ def build_webext_dictionary_from_legacy(addon, destination):
|
||||||
|
|
||||||
manifest = {
|
manifest = {
|
||||||
'manifest_version': 2,
|
'manifest_version': 2,
|
||||||
'name': six.text_type(addon.name),
|
'name': str(addon.name),
|
||||||
'browser_specific_settings': {
|
'browser_specific_settings': {
|
||||||
'gecko': {
|
'gecko': {
|
||||||
'id': addon.guid,
|
'id': addon.guid,
|
||||||
|
|
|
@ -4,8 +4,6 @@ from django.contrib.syndication.views import Feed
|
||||||
from django.db.transaction import non_atomic_requests
|
from django.db.transaction import non_atomic_requests
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
class BaseFeed(Feed):
|
class BaseFeed(Feed):
|
||||||
"""
|
"""
|
||||||
|
@ -43,5 +41,5 @@ class BaseFeed(Feed):
|
||||||
'title'
|
'title'
|
||||||
)
|
)
|
||||||
if data and attname in problematic_keys:
|
if data and attname in problematic_keys:
|
||||||
data = re.sub(self.CONTROL_CHARS_REGEXP, '', six.text_type(data))
|
data = re.sub(self.CONTROL_CHARS_REGEXP, '', str(data))
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import olympia.core.logger
|
import olympia.core.logger
|
||||||
|
|
||||||
from olympia.constants.search import SEARCH_ANALYZER_MAP
|
from olympia.constants.search import SEARCH_ANALYZER_MAP
|
||||||
|
@ -141,7 +139,7 @@ class BaseSearchIndexer(object):
|
||||||
|
|
||||||
extend_with_me = {
|
extend_with_me = {
|
||||||
'%s_translations' % field: [
|
'%s_translations' % field: [
|
||||||
{'lang': to_language(lang), 'string': six.text_type(string)}
|
{'lang': to_language(lang), 'string': str(string)}
|
||||||
for lang, string in obj.translations[getattr(obj, db_field)]
|
for lang, string in obj.translations[getattr(obj, db_field)]
|
||||||
if string
|
if string
|
||||||
]
|
]
|
||||||
|
@ -162,9 +160,7 @@ class BaseSearchIndexer(object):
|
||||||
default_locale = default_locale.lower() if default_locale else None
|
default_locale = default_locale.lower() if default_locale else None
|
||||||
value = translations.get(default_locale, getattr(obj, field))
|
value = translations.get(default_locale, getattr(obj, field))
|
||||||
|
|
||||||
return {
|
return {field: str(value) if value else ''}
|
||||||
field: six.text_type(value) if value else ''
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def extract_field_analyzed_translations(cls, obj, field, db_field=None):
|
def extract_field_analyzed_translations(cls, obj, field, db_field=None):
|
||||||
|
@ -179,9 +175,9 @@ class BaseSearchIndexer(object):
|
||||||
|
|
||||||
# Indices for each language. languages is a list of locales we want to
|
# Indices for each language. languages is a list of locales we want to
|
||||||
# index with analyzer if the string's locale matches.
|
# index with analyzer if the string's locale matches.
|
||||||
for analyzer, languages in six.iteritems(SEARCH_ANALYZER_MAP):
|
for analyzer, languages in SEARCH_ANALYZER_MAP.items():
|
||||||
extend_with_me['%s_l10n_%s' % (field, analyzer)] = list(
|
extend_with_me['%s_l10n_%s' % (field, analyzer)] = list(
|
||||||
set(six.text_type(string) for locale, string
|
set(str(string) for locale, string
|
||||||
in obj.translations[getattr(obj, db_field)]
|
in obj.translations[getattr(obj, db_field)]
|
||||||
if locale.lower() in languages and string))
|
if locale.lower() in languages and string))
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.contrib.staticfiles.finders import find as find_static_path
|
from django.contrib.staticfiles.finders import find as find_static_path
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.lib.jingo_minify_helpers import ensure_path_exists
|
from olympia.lib.jingo_minify_helpers import ensure_path_exists
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,8 +71,8 @@ class Command(BaseCommand):
|
||||||
# - Concat all files into one
|
# - Concat all files into one
|
||||||
# - Cache bust all images in CSS files
|
# - Cache bust all images in CSS files
|
||||||
# - Minify the concatted files
|
# - Minify the concatted files
|
||||||
for ftype, bundle in six.iteritems(settings.MINIFY_BUNDLES):
|
for ftype, bundle in settings.MINIFY_BUNDLES.items():
|
||||||
for name, files in six.iteritems(bundle):
|
for name, files in bundle.items():
|
||||||
# Set the paths to the files.
|
# Set the paths to the files.
|
||||||
concatted_file = os.path.join(
|
concatted_file = os.path.join(
|
||||||
settings.ROOT, 'static',
|
settings.ROOT, 'static',
|
||||||
|
|
|
@ -5,7 +5,6 @@ from django.template import loader
|
||||||
from django.utils import safestring
|
from django.utils import safestring
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
|
@ -53,10 +52,10 @@ def _is_dupe(msg, request):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
smsg = six.text_type(msg)
|
smsg = str(msg)
|
||||||
is_dupe = False
|
is_dupe = False
|
||||||
for message in storage:
|
for message in storage:
|
||||||
if six.text_type(message) == smsg:
|
if str(message) == smsg:
|
||||||
# We can't return from here because we need to tell Django not
|
# We can't return from here because we need to tell Django not
|
||||||
# to consume the messages.
|
# to consume the messages.
|
||||||
is_dupe = True
|
is_dupe = True
|
||||||
|
|
|
@ -3,6 +3,8 @@ import re
|
||||||
import socket
|
import socket
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.middleware import AuthenticationMiddleware
|
from django.contrib.auth.middleware import AuthenticationMiddleware
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
@ -19,7 +21,6 @@ from django.utils.encoding import force_text, iri_to_uri
|
||||||
from django.utils.translation import activate, ugettext_lazy as _
|
from django.utils.translation import activate, ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from six.moves.urllib.parse import quote
|
|
||||||
|
|
||||||
import MySQLdb as mysql
|
import MySQLdb as mysql
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import os
|
import os
|
||||||
|
import io
|
||||||
import socket
|
import socket
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import six
|
|
||||||
|
|
||||||
from kombu import Connection
|
from kombu import Connection
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
@ -64,7 +64,7 @@ def libraries():
|
||||||
libraries_results = []
|
libraries_results = []
|
||||||
status = ''
|
status = ''
|
||||||
try:
|
try:
|
||||||
Image.new('RGB', (16, 16)).save(six.BytesIO(), 'JPEG')
|
Image.new('RGB', (16, 16)).save(io.BytesIO(), 'JPEG')
|
||||||
libraries_results.append(('PIL+JPEG', True, 'Got it!'))
|
libraries_results.append(('PIL+JPEG', True, 'Got it!'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = "Failed to create a jpeg image: %s" % e
|
msg = "Failed to create a jpeg image: %s" % e
|
||||||
|
|
|
@ -2,6 +2,8 @@ import json as jsonlib
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.forms import CheckboxInput
|
from django.forms import CheckboxInput
|
||||||
|
@ -14,14 +16,12 @@ from django.utils.translation import (
|
||||||
get_language, to_locale, trim_whitespace, ugettext)
|
get_language, to_locale, trim_whitespace, ugettext)
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from babel.support import Format
|
from babel.support import Format
|
||||||
from django_jinja import library
|
from django_jinja import library
|
||||||
from rest_framework.reverse import reverse as drf_reverse
|
from rest_framework.reverse import reverse as drf_reverse
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from six.moves.urllib_parse import urljoin
|
|
||||||
|
|
||||||
from olympia.amo import urlresolvers, utils
|
from olympia.amo import urlresolvers, utils
|
||||||
from olympia.constants.licenses import PERSONA_LICENSES_IDS
|
from olympia.constants.licenses import PERSONA_LICENSES_IDS
|
||||||
|
@ -38,7 +38,7 @@ library.global_function(utils.randslice)
|
||||||
|
|
||||||
# Mark a lazy marked instance as safe but keep
|
# Mark a lazy marked instance as safe but keep
|
||||||
# it lazy
|
# it lazy
|
||||||
mark_safe_lazy = lazy(mark_safe, six.text_type)
|
mark_safe_lazy = lazy(mark_safe, str)
|
||||||
|
|
||||||
|
|
||||||
@library.global_function
|
@library.global_function
|
||||||
|
@ -205,14 +205,14 @@ def strip_controls(s):
|
||||||
"""
|
"""
|
||||||
# Translation table of control characters.
|
# Translation table of control characters.
|
||||||
control_trans = dict((n, None) for n in range(32) if n not in [10, 13])
|
control_trans = dict((n, None) for n in range(32) if n not in [10, 13])
|
||||||
rv = six.text_type(s).translate(control_trans)
|
rv = str(s).translate(control_trans)
|
||||||
return jinja2.Markup(rv) if isinstance(s, jinja2.Markup) else rv
|
return jinja2.Markup(rv) if isinstance(s, jinja2.Markup) else rv
|
||||||
|
|
||||||
|
|
||||||
@library.filter
|
@library.filter
|
||||||
def external_url(url):
|
def external_url(url):
|
||||||
"""Bounce a URL off outgoing.prod.mozaws.net."""
|
"""Bounce a URL off outgoing.prod.mozaws.net."""
|
||||||
return urlresolvers.get_outgoing_url(six.text_type(url))
|
return urlresolvers.get_outgoing_url(str(url))
|
||||||
|
|
||||||
|
|
||||||
@library.filter
|
@library.filter
|
||||||
|
@ -227,7 +227,7 @@ def license_link(license):
|
||||||
"""Link to a code license, including icon where applicable."""
|
"""Link to a code license, including icon where applicable."""
|
||||||
# If passed in an integer, try to look up the License.
|
# If passed in an integer, try to look up the License.
|
||||||
from olympia.versions.models import License
|
from olympia.versions.models import License
|
||||||
if isinstance(license, six.integer_types):
|
if isinstance(license, int):
|
||||||
if license in PERSONA_LICENSES_IDS:
|
if license in PERSONA_LICENSES_IDS:
|
||||||
# Grab built-in license.
|
# Grab built-in license.
|
||||||
license = PERSONA_LICENSES_IDS[license]
|
license = PERSONA_LICENSES_IDS[license]
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import shutil
|
import shutil
|
||||||
import six
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
@ -11,7 +10,7 @@ from contextlib import contextmanager
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from six.moves.urllib_parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
from django import forms, test
|
from django import forms, test
|
||||||
|
@ -191,7 +190,7 @@ def check_links(expected, elements, selected=None, verify=True):
|
||||||
if isinstance(item, tuple):
|
if isinstance(item, tuple):
|
||||||
text, link = item
|
text, link = item
|
||||||
# Or list item could be `link`.
|
# Or list item could be `link`.
|
||||||
elif isinstance(item, six.string_types):
|
elif isinstance(item, str):
|
||||||
text, link = None, item
|
text, link = None, item
|
||||||
|
|
||||||
e = elements.eq(idx)
|
e = elements.eq(idx)
|
||||||
|
@ -211,8 +210,8 @@ def check_links(expected, elements, selected=None, verify=True):
|
||||||
|
|
||||||
def assert_url_equal(url, expected, compare_host=False):
|
def assert_url_equal(url, expected, compare_host=False):
|
||||||
"""Compare url paths and query strings."""
|
"""Compare url paths and query strings."""
|
||||||
parsed = urlparse(six.text_type(url))
|
parsed = urlparse(str(url))
|
||||||
parsed_expected = urlparse(six.text_type(expected))
|
parsed_expected = urlparse(str(expected))
|
||||||
compare_url_part(parsed.path, parsed_expected.path)
|
compare_url_part(parsed.path, parsed_expected.path)
|
||||||
compare_url_part(parse_qs(parsed.query), parse_qs(parsed_expected.query))
|
compare_url_part(parse_qs(parsed.query), parse_qs(parsed_expected.query))
|
||||||
if compare_host:
|
if compare_host:
|
||||||
|
@ -464,7 +463,7 @@ class TestCase(PatchMixin, InitializeSessionMixin, test.TestCase):
|
||||||
# There are multiple contexts so iter all of them.
|
# There are multiple contexts so iter all of them.
|
||||||
tpl = response.context
|
tpl = response.context
|
||||||
for ctx in tpl:
|
for ctx in tpl:
|
||||||
for k, v in six.iteritems(ctx):
|
for k, v in ctx.items():
|
||||||
if isinstance(v, (forms.BaseForm, forms.formsets.BaseFormSet)):
|
if isinstance(v, (forms.BaseForm, forms.formsets.BaseFormSet)):
|
||||||
if isinstance(v, forms.formsets.BaseFormSet):
|
if isinstance(v, forms.formsets.BaseFormSet):
|
||||||
# Concatenate errors from each form in the formset.
|
# Concatenate errors from each form in the formset.
|
||||||
|
@ -495,7 +494,7 @@ class TestCase(PatchMixin, InitializeSessionMixin, test.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Try parsing the string if it's not a datetime.
|
# Try parsing the string if it's not a datetime.
|
||||||
if isinstance(dt, six.string_types):
|
if isinstance(dt, str):
|
||||||
try:
|
try:
|
||||||
dt = dateutil_parser(dt)
|
dt = dateutil_parser(dt)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
@ -670,8 +669,7 @@ def addon_factory(
|
||||||
default_locale = kw.get('default_locale', settings.LANGUAGE_CODE)
|
default_locale = kw.get('default_locale', settings.LANGUAGE_CODE)
|
||||||
|
|
||||||
# Keep as much unique data as possible in the uuid: '-' aren't important.
|
# Keep as much unique data as possible in the uuid: '-' aren't important.
|
||||||
name = kw.pop('name', u'Addôn %s' %
|
name = kw.pop('name', u'Addôn %s' % str(uuid.uuid4()).replace('-', ''))
|
||||||
six.text_type(uuid.uuid4()).replace('-', ''))
|
|
||||||
slug = kw.pop('slug', None)
|
slug = kw.pop('slug', None)
|
||||||
if slug is None:
|
if slug is None:
|
||||||
slug = name.replace(' ', '-').lower()[:30]
|
slug = name.replace(' ', '-').lower()[:30]
|
||||||
|
@ -696,7 +694,7 @@ def addon_factory(
|
||||||
kwargs['summary'] = u'Summary for %s' % name
|
kwargs['summary'] = u'Summary for %s' % name
|
||||||
if type_ not in [amo.ADDON_PERSONA, amo.ADDON_SEARCH]:
|
if type_ not in [amo.ADDON_PERSONA, amo.ADDON_SEARCH]:
|
||||||
# Personas and search engines don't need guids
|
# Personas and search engines don't need guids
|
||||||
kwargs['guid'] = kw.pop('guid', '{%s}' % six.text_type(uuid.uuid4()))
|
kwargs['guid'] = kw.pop('guid', '{%s}' % str(uuid.uuid4()))
|
||||||
kwargs.update(kw)
|
kwargs.update(kw)
|
||||||
|
|
||||||
# Save 1.
|
# Save 1.
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
|
import io
|
||||||
|
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -9,7 +11,6 @@ from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
def sample_cron_job(*args):
|
def sample_cron_job(*args):
|
||||||
|
@ -42,7 +43,7 @@ def test_cron_command_invalid_job():
|
||||||
|
|
||||||
|
|
||||||
def test_cron_jobs_setting():
|
def test_cron_jobs_setting():
|
||||||
for name, path in six.iteritems(settings.CRON_JOBS):
|
for name, path in settings.CRON_JOBS.items():
|
||||||
module = import_module(path)
|
module = import_module(path)
|
||||||
getattr(module, name)
|
getattr(module, name)
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ def test_compress_assets_command_without_git():
|
||||||
|
|
||||||
# Capture output to avoid it being logged and allow us to validate it
|
# Capture output to avoid it being logged and allow us to validate it
|
||||||
# later if needed
|
# later if needed
|
||||||
out = six.StringIO()
|
out = io.StringIO()
|
||||||
call_command('compress_assets', stdout=out)
|
call_command('compress_assets', stdout=out)
|
||||||
|
|
||||||
build_id_file = os.path.realpath(os.path.join(settings.ROOT, 'build.py'))
|
build_id_file = os.path.realpath(os.path.join(settings.ROOT, 'build.py'))
|
||||||
|
@ -86,7 +87,7 @@ def test_compress_assets_correctly_fetches_static_images(settings, tmpdir):
|
||||||
|
|
||||||
# Capture output to avoid it being logged and allow us to validate it
|
# Capture output to avoid it being logged and allow us to validate it
|
||||||
# later if needed
|
# later if needed
|
||||||
out = six.StringIO()
|
out = io.StringIO()
|
||||||
|
|
||||||
# Now run compress and collectstatic
|
# Now run compress and collectstatic
|
||||||
call_command('compress_assets', force=True, stdout=out)
|
call_command('compress_assets', force=True, stdout=out)
|
||||||
|
|
|
@ -3,7 +3,8 @@ import mimetypes
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from six.moves.urllib_parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
|
@ -14,7 +15,6 @@ from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from unittest.mock import Mock, patch
|
|
||||||
from pyquery import PyQuery
|
from pyquery import PyQuery
|
||||||
|
|
||||||
import olympia
|
import olympia
|
||||||
|
|
|
@ -3,7 +3,6 @@ from django import test
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
|
@ -77,28 +76,14 @@ def test_source_with_wrong_unicode_get():
|
||||||
response = test.Client().get('/firefox/collections/mozmj/autumn/'
|
response = test.Client().get('/firefox/collections/mozmj/autumn/'
|
||||||
'?source=firefoxsocialmedia\x14\x85')
|
'?source=firefoxsocialmedia\x14\x85')
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
# Django's behaviour for URLs containing unicode characters is different
|
assert response['Location'].endswith(
|
||||||
# under Python 2 and 3. This is fine though, as browsers should send URLs
|
'?source=firefoxsocialmedia%14%C3%82%C2%85')
|
||||||
# urlencoded, and that's tested above in test_redirect_with_unicode_get().
|
|
||||||
# We just need to make sure we're not crashing on such URLs.
|
|
||||||
if six.PY2:
|
|
||||||
assert response['Location'].endswith('?source=firefoxsocialmedia%14')
|
|
||||||
else:
|
|
||||||
assert response['Location'].endswith(
|
|
||||||
'?source=firefoxsocialmedia%14%C3%82%C2%85')
|
|
||||||
|
|
||||||
|
|
||||||
def test_trailing_slash_middleware():
|
def test_trailing_slash_middleware():
|
||||||
response = test.Client().get(u'/en-US/about/?xxx=\xc3')
|
response = test.Client().get(u'/en-US/about/?xxx=\xc3')
|
||||||
assert response.status_code == 301
|
assert response.status_code == 301
|
||||||
# Django's behaviour for URLs containing unicode characters is different
|
assert response['Location'].endswith('/en-US/about?xxx=%C3%83%C2%83')
|
||||||
# under Python 2 and 3. This is fine though, as browsers should send URLs
|
|
||||||
# urlencoded, and that's tested above in test_redirect_with_unicode_get().
|
|
||||||
# We just need to make sure we're not crashing on such URLs.
|
|
||||||
if six.PY2:
|
|
||||||
assert response['Location'].endswith('/en-US/about?xxx=%C3%83')
|
|
||||||
else:
|
|
||||||
assert response['Location'].endswith('/en-US/about?xxx=%C3%83%C2%83')
|
|
||||||
|
|
||||||
|
|
||||||
class AdminMessageTest(TestCase):
|
class AdminMessageTest(TestCase):
|
||||||
|
@ -140,7 +125,7 @@ def test_request_id_middleware(client):
|
||||||
"""Test that we add a request id to every response"""
|
"""Test that we add a request id to every response"""
|
||||||
response = client.get(reverse('devhub.index'))
|
response = client.get(reverse('devhub.index'))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert isinstance(response['X-AMO-Request-ID'], six.string_types)
|
assert isinstance(response['X-AMO-Request-ID'], str)
|
||||||
|
|
||||||
# Test that we set `request.request_id` too
|
# Test that we set `request.request_id` too
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ from django.core.paginator import (
|
||||||
EmptyPage, InvalidPage, PageNotAnInteger, Paginator)
|
EmptyPage, InvalidPage, PageNotAnInteger, Paginator)
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import MagicMock, Mock
|
from unittest.mock import MagicMock, Mock
|
||||||
|
|
||||||
|
@ -107,7 +106,7 @@ class TestSearchPaginator(TestCase):
|
||||||
# unfortunately since `pytest.raises` won't check the exact
|
# unfortunately since `pytest.raises` won't check the exact
|
||||||
# instance but also accepts parent exceptions inherited.
|
# instance but also accepts parent exceptions inherited.
|
||||||
assert (
|
assert (
|
||||||
six.text_type(exc.value) ==
|
str(exc.value) ==
|
||||||
'That page number is too high for the current page size')
|
'That page number is too high for the current page size')
|
||||||
assert isinstance(exc.value, InvalidPage)
|
assert isinstance(exc.value, InvalidPage)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.core.mail import EmailMessage
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from celery.exceptions import Retry
|
from celery.exceptions import Retry
|
||||||
|
|
||||||
|
@ -213,7 +212,7 @@ class TestSendMail(TestCase):
|
||||||
assert '<a href' not in message1, 'text-only email contained HTML!'
|
assert '<a href' not in message1, 'text-only email contained HTML!'
|
||||||
assert '<a href' in message2, 'HTML email did not contain HTML!'
|
assert '<a href' in message2, 'HTML email did not contain HTML!'
|
||||||
|
|
||||||
unsubscribe_msg = six.text_type(notifications.individual_contact.label)
|
unsubscribe_msg = str(notifications.individual_contact.label)
|
||||||
assert unsubscribe_msg in message1
|
assert unsubscribe_msg in message1
|
||||||
assert unsubscribe_msg in message2
|
assert unsubscribe_msg in message2
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ def test_base_paths_bytestring(key):
|
||||||
|
|
||||||
See https://github.com/mozilla/addons-server/issues/3579 for context.
|
See https://github.com/mozilla/addons-server/issues/3579 for context.
|
||||||
"""
|
"""
|
||||||
assert isinstance(getattr(settings, key), six.string_types)
|
assert isinstance(getattr(settings, key), str)
|
||||||
|
|
||||||
|
|
||||||
def test_raven_release_config():
|
def test_raven_release_config():
|
||||||
|
|
|
@ -9,7 +9,6 @@ from django.utils.functional import cached_property
|
||||||
import freezegun
|
import freezegun
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from babel import Locale
|
from babel import Locale
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ class TestAttachTransDict(TestCase):
|
||||||
# it for __str__. We depend on this behaviour later in the test.
|
# it for __str__. We depend on this behaviour later in the test.
|
||||||
assert '<script>' in addon.description.localized_string
|
assert '<script>' in addon.description.localized_string
|
||||||
assert '<script>' not in addon.description.localized_string_clean
|
assert '<script>' not in addon.description.localized_string_clean
|
||||||
assert '<script>' not in six.text_type(addon.description)
|
assert '<script>' not in str(addon.description)
|
||||||
|
|
||||||
# Attach trans dict.
|
# Attach trans dict.
|
||||||
attach_trans_dict(Addon, [addon])
|
attach_trans_dict(Addon, [addon])
|
||||||
|
@ -60,18 +59,15 @@ class TestAttachTransDict(TestCase):
|
||||||
|
|
||||||
# Build expected translations dict.
|
# Build expected translations dict.
|
||||||
expected_translations = {
|
expected_translations = {
|
||||||
addon.eula_id: [('en-us', six.text_type(addon.eula))],
|
addon.eula_id: [('en-us', str(addon.eula))],
|
||||||
addon.description_id: [
|
addon.description_id: [('en-us', str(addon.description))],
|
||||||
('en-us', six.text_type(addon.description))],
|
|
||||||
addon.developer_comments_id:
|
addon.developer_comments_id:
|
||||||
[('en-us', six.text_type(addon.developer_comments))],
|
[('en-us', str(addon.developer_comments))],
|
||||||
addon.summary_id: [('en-us', six.text_type(addon.summary))],
|
addon.summary_id: [('en-us', str(addon.summary))],
|
||||||
addon.homepage_id: [('en-us', six.text_type(addon.homepage))],
|
addon.homepage_id: [('en-us', str(addon.homepage))],
|
||||||
addon.name_id: [('en-us', six.text_type(addon.name))],
|
addon.name_id: [('en-us', str(addon.name))],
|
||||||
addon.support_email_id: [
|
addon.support_email_id: [('en-us', str(addon.support_email))],
|
||||||
('en-us', six.text_type(addon.support_email))],
|
addon.support_url_id: [('en-us', str(addon.support_url))]
|
||||||
addon.support_url_id: [
|
|
||||||
('en-us', six.text_type(addon.support_url))]
|
|
||||||
}
|
}
|
||||||
assert translations == expected_translations
|
assert translations == expected_translations
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from unittest import mock
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django import test
|
from django import test
|
||||||
|
@ -11,13 +13,11 @@ from django.conf import settings
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from six.moves.urllib_parse import urlparse
|
|
||||||
|
|
||||||
from olympia import amo, core
|
from olympia import amo, core
|
||||||
from olympia.access import acl
|
from olympia.access import acl
|
||||||
|
|
|
@ -4,6 +4,7 @@ import hmac
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from threading import local
|
from threading import local
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
from django import urls
|
from django import urls
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -13,9 +14,7 @@ from django.utils.translation.trans_real import parse_accept_lang_header
|
||||||
|
|
||||||
import bleach
|
import bleach
|
||||||
import jinja2
|
import jinja2
|
||||||
import six
|
|
||||||
|
|
||||||
from six.moves.urllib_parse import quote
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
|
||||||
|
@ -241,13 +240,13 @@ def linkify_escape(text):
|
||||||
# Parameters are already escaped.
|
# Parameters are already escaped.
|
||||||
return u'<a href="{0}">{0}</a>'.format(match.group(0))
|
return u'<a href="{0}">{0}</a>'.format(match.group(0))
|
||||||
|
|
||||||
return URL_RE.sub(linkify, six.text_type(jinja2.escape(text)))
|
return URL_RE.sub(linkify, str(jinja2.escape(text)))
|
||||||
|
|
||||||
|
|
||||||
def linkify_with_outgoing(text):
|
def linkify_with_outgoing(text):
|
||||||
"""Wrapper around bleach.linkify: uses get_outgoing_url."""
|
"""Wrapper around bleach.linkify: uses get_outgoing_url."""
|
||||||
callbacks = [linkify_bounce_url_callback, bleach.callbacks.nofollow]
|
callbacks = [linkify_bounce_url_callback, bleach.callbacks.nofollow]
|
||||||
return bleach.linkify(six.text_type(text), callbacks=callbacks)
|
return bleach.linkify(str(text), callbacks=callbacks)
|
||||||
|
|
||||||
|
|
||||||
def lang_from_accept_header(header):
|
def lang_from_accept_header(header):
|
||||||
|
|
|
@ -11,13 +11,13 @@ import random
|
||||||
import re
|
import re
|
||||||
import scandir
|
import scandir
|
||||||
import shutil
|
import shutil
|
||||||
import six
|
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
from six.moves.urllib_parse import parse_qsl, ParseResult, unquote_to_bytes
|
from urllib.parse import (
|
||||||
|
parse_qsl, ParseResult, unquote_to_bytes, urlencode as urllib_urlencode)
|
||||||
|
|
||||||
import django.core.mail
|
import django.core.mail
|
||||||
|
|
||||||
|
@ -221,12 +221,12 @@ def send_mail(subject, message, from_email=None, recipient_list=None,
|
||||||
if not recipient_list:
|
if not recipient_list:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if isinstance(recipient_list, six.string_types):
|
if isinstance(recipient_list, str):
|
||||||
raise ValueError('recipient_list should be a list, not a string.')
|
raise ValueError('recipient_list should be a list, not a string.')
|
||||||
|
|
||||||
# Check against user notification settings
|
# Check against user notification settings
|
||||||
if perm_setting:
|
if perm_setting:
|
||||||
if isinstance(perm_setting, six.string_types):
|
if isinstance(perm_setting, str):
|
||||||
perm_setting = notifications.NOTIFICATIONS_BY_SHORT[perm_setting]
|
perm_setting = notifications.NOTIFICATIONS_BY_SHORT[perm_setting]
|
||||||
perms = dict(UserNotification.objects
|
perms = dict(UserNotification.objects
|
||||||
.filter(user__email__in=recipient_list,
|
.filter(user__email__in=recipient_list,
|
||||||
|
@ -252,8 +252,8 @@ def send_mail(subject, message, from_email=None, recipient_list=None,
|
||||||
from_email = settings.DEFAULT_FROM_EMAIL
|
from_email = settings.DEFAULT_FROM_EMAIL
|
||||||
|
|
||||||
if cc:
|
if cc:
|
||||||
# If not six.string_types, assume it is already a list.
|
# If not str, assume it is already a list.
|
||||||
if isinstance(cc, six.string_types):
|
if isinstance(cc, str):
|
||||||
cc = [cc]
|
cc = [cc]
|
||||||
|
|
||||||
if not headers:
|
if not headers:
|
||||||
|
@ -444,10 +444,9 @@ def chunked(seq, n):
|
||||||
def urlencode(items):
|
def urlencode(items):
|
||||||
"""A Unicode-safe URLencoder."""
|
"""A Unicode-safe URLencoder."""
|
||||||
try:
|
try:
|
||||||
return six.moves.urllib_parse.urlencode(items)
|
return urllib_urlencode(items)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
return six.moves.urllib_parse.urlencode(
|
return urllib_urlencode([(k, force_bytes(v)) for k, v in items])
|
||||||
[(k, force_bytes(v)) for k, v in items])
|
|
||||||
|
|
||||||
|
|
||||||
def randslice(qs, limit, exclude=None):
|
def randslice(qs, limit, exclude=None):
|
||||||
|
@ -750,7 +749,7 @@ class HttpResponseSendFile(HttpResponse):
|
||||||
super(HttpResponseSendFile, self).__init__('', status=status,
|
super(HttpResponseSendFile, self).__init__('', status=status,
|
||||||
content_type=content_type)
|
content_type=content_type)
|
||||||
header_path = self.path
|
header_path = self.path
|
||||||
if isinstance(header_path, six.text_type):
|
if isinstance(header_path, str):
|
||||||
header_path = header_path.encode('utf8')
|
header_path = header_path.encode('utf8')
|
||||||
if settings.XSENDFILE:
|
if settings.XSENDFILE:
|
||||||
self[settings.XSENDFILE_HEADER] = header_path
|
self[settings.XSENDFILE_HEADER] = header_path
|
||||||
|
@ -821,7 +820,7 @@ def escape_all(value):
|
||||||
Only linkify full urls, including a scheme, if "linkify_only_full" is True.
|
Only linkify full urls, including a scheme, if "linkify_only_full" is True.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(value, six.string_types):
|
if isinstance(value, str):
|
||||||
value = jinja2.escape(force_text(value))
|
value = jinja2.escape(force_text(value))
|
||||||
value = linkify_with_outgoing(value)
|
value = linkify_with_outgoing(value)
|
||||||
return value
|
return value
|
||||||
|
@ -829,7 +828,7 @@ def escape_all(value):
|
||||||
for i, lv in enumerate(value):
|
for i, lv in enumerate(value):
|
||||||
value[i] = escape_all(lv)
|
value[i] = escape_all(lv)
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
for k, lv in six.iteritems(value):
|
for k, lv in value.items():
|
||||||
value[k] = escape_all(lv)
|
value[k] = escape_all(lv)
|
||||||
elif isinstance(value, Translation):
|
elif isinstance(value, Translation):
|
||||||
value = jinja2.escape(force_text(value))
|
value = jinja2.escape(force_text(value))
|
||||||
|
@ -903,7 +902,7 @@ def attach_trans_dict(model, objs):
|
||||||
converted_translation = new_class()
|
converted_translation = new_class()
|
||||||
converted_translation.__dict__ = translation.__dict__
|
converted_translation.__dict__ = translation.__dict__
|
||||||
return (converted_translation.locale.lower(),
|
return (converted_translation.locale.lower(),
|
||||||
six.text_type(converted_translation))
|
str(converted_translation))
|
||||||
|
|
||||||
# Build and attach translations for each field on each object.
|
# Build and attach translations for each field on each object.
|
||||||
for obj in objs:
|
for obj in objs:
|
||||||
|
|
|
@ -10,8 +10,6 @@ from django.db.transaction import non_atomic_requests
|
||||||
from django.http import HttpResponse, JsonResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from django_statsd.clients import statsd
|
from django_statsd.clients import statsd
|
||||||
from rest_framework.exceptions import NotFound
|
from rest_framework.exceptions import NotFound
|
||||||
|
|
||||||
|
@ -78,7 +76,7 @@ def handler404(request, exception=None, **kwargs):
|
||||||
if request.is_api:
|
if request.is_api:
|
||||||
# It's a v3+ api request
|
# It's a v3+ api request
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{'detail': six.text_type(NotFound.default_detail)}, status=404)
|
{'detail': str(NotFound.default_detail)}, status=404)
|
||||||
# X_IS_MOBILE_AGENTS is set by nginx as an env variable when it detects
|
# X_IS_MOBILE_AGENTS is set by nginx as an env variable when it detects
|
||||||
# a mobile User Agent or when the mamo cookie is present.
|
# a mobile User Agent or when the mamo cookie is present.
|
||||||
if request.META.get('X_IS_MOBILE_AGENTS') == '1':
|
if request.META.get('X_IS_MOBILE_AGENTS') == '1':
|
||||||
|
|
|
@ -3,8 +3,6 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import get_language, ugettext_lazy as _
|
from django.utils.translation import get_language, ugettext_lazy as _
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework import fields, serializers
|
from rest_framework import fields, serializers
|
||||||
|
|
||||||
from olympia.amo.utils import to_language
|
from olympia.amo.utils import to_language
|
||||||
|
@ -96,13 +94,11 @@ class TranslationSerializerField(fields.Field):
|
||||||
def fetch_all_translations(self, obj, source, field):
|
def fetch_all_translations(self, obj, source, field):
|
||||||
translations = field.__class__.objects.filter(
|
translations = field.__class__.objects.filter(
|
||||||
id=field.id, localized_string__isnull=False)
|
id=field.id, localized_string__isnull=False)
|
||||||
return {to_language(trans.locale): six.text_type(trans)
|
return {to_language(trans.locale): str(trans)
|
||||||
for trans in translations} if translations else None
|
for trans in translations} if translations else None
|
||||||
|
|
||||||
def fetch_single_translation(self, obj, source, field, requested_language):
|
def fetch_single_translation(self, obj, source, field, requested_language):
|
||||||
return (
|
return {to_language(field.locale): str(field)} if field else None
|
||||||
{to_language(field.locale): six.text_type(field)} if field
|
|
||||||
else None)
|
|
||||||
|
|
||||||
def get_attribute(self, obj):
|
def get_attribute(self, obj):
|
||||||
source = self.source or self.field_name
|
source = self.source or self.field_name
|
||||||
|
@ -128,7 +124,7 @@ class TranslationSerializerField(fields.Field):
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
if isinstance(data, six.string_types):
|
if isinstance(data, str):
|
||||||
self.validate(data)
|
self.validate(data)
|
||||||
return data.strip()
|
return data.strip()
|
||||||
elif isinstance(data, dict):
|
elif isinstance(data, dict):
|
||||||
|
@ -136,7 +132,7 @@ class TranslationSerializerField(fields.Field):
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
data[key] = value and value.strip()
|
data[key] = value and value.strip()
|
||||||
return data
|
return data
|
||||||
return six.text_type(data)
|
return str(data)
|
||||||
|
|
||||||
def validate(self, value):
|
def validate(self, value):
|
||||||
if not self.flat and not isinstance(value, dict):
|
if not self.flat and not isinstance(value, dict):
|
||||||
|
@ -146,7 +142,7 @@ class TranslationSerializerField(fields.Field):
|
||||||
|
|
||||||
value_too_short = True
|
value_too_short = True
|
||||||
|
|
||||||
if isinstance(value, six.string_types):
|
if isinstance(value, str):
|
||||||
if self.min_length and len(value.strip()) >= self.min_length:
|
if self.min_length and len(value.strip()) >= self.min_length:
|
||||||
value_too_short = False
|
value_too_short = False
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import csv
|
import csv
|
||||||
import six
|
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
@ -11,7 +10,7 @@ class Command(BaseCommand):
|
||||||
help = 'Revoke the API (secret, key) tuples from specified csv file.'
|
help = 'Revoke the API (secret, key) tuples from specified csv file.'
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('csv_file', type=six.text_type)
|
parser.add_argument('csv_file', type=str)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
revoked_count = 0
|
revoked_count = 0
|
||||||
|
|
|
@ -3,7 +3,7 @@ import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
from aesfield.field import AESField
|
from aesfield.field import AESField
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ API_KEY_TYPES = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class APIKey(ModelBase):
|
class APIKey(ModelBase):
|
||||||
"""
|
"""
|
||||||
A developer's key/secret pair to access the API.
|
A developer's key/secret pair to access the API.
|
||||||
|
|
|
@ -3,6 +3,7 @@ import time
|
||||||
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
|
@ -11,8 +12,6 @@ from django.urls import reverse
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
from unittest import mock
|
|
||||||
import six
|
|
||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from rest_framework.exceptions import AuthenticationFailed
|
from rest_framework.exceptions import AuthenticationFailed
|
||||||
|
@ -77,8 +76,8 @@ class TestJWTKeyAuthentication(JWTAuthKeyTester, TestCase):
|
||||||
issued_at = int(time.mktime(datetime.utcnow().timetuple()))
|
issued_at = int(time.mktime(datetime.utcnow().timetuple()))
|
||||||
payload = {
|
payload = {
|
||||||
'iss': api_key.key,
|
'iss': api_key.key,
|
||||||
'iat': six.text_type(issued_at),
|
'iat': str(issued_at),
|
||||||
'exp': six.text_type(
|
'exp': str(
|
||||||
issued_at + settings.MAX_APIKEY_JWT_AUTH_TOKEN_LIFETIME),
|
issued_at + settings.MAX_APIKEY_JWT_AUTH_TOKEN_LIFETIME),
|
||||||
}
|
}
|
||||||
token = self.encode_token_payload(payload, api_key.secret)
|
token = self.encode_token_payload(payload, api_key.secret)
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import os.path
|
import os.path
|
||||||
|
import io
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
|
|
||||||
from six import StringIO
|
|
||||||
|
|
||||||
from olympia.amo.tests import TestCase, user_factory
|
from olympia.amo.tests import TestCase, user_factory
|
||||||
from olympia.api.models import APIKey
|
from olympia.api.models import APIKey
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ class TestRevokeAPIKeys(TestCase):
|
||||||
# The test csv does not contain an entry for this user.
|
# The test csv does not contain an entry for this user.
|
||||||
apikey = APIKey.new_jwt_credentials(user=user)
|
apikey = APIKey.new_jwt_credentials(user=user)
|
||||||
old_secret = apikey.secret
|
old_secret = apikey.secret
|
||||||
stdout = StringIO()
|
stdout = io.StringIO()
|
||||||
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
||||||
stdout.seek(0)
|
stdout.seek(0)
|
||||||
output = stdout.readlines()
|
output = stdout.readlines()
|
||||||
|
@ -44,7 +43,7 @@ class TestRevokeAPIKeys(TestCase):
|
||||||
apikey = APIKey.objects.create(
|
apikey = APIKey.objects.create(
|
||||||
key='user:{}:{}'.format(user.pk, '333'), secret=right_secret,
|
key='user:{}:{}'.format(user.pk, '333'), secret=right_secret,
|
||||||
user=user, is_active=None) # inactive APIKey.
|
user=user, is_active=None) # inactive APIKey.
|
||||||
stdout = StringIO()
|
stdout = io.StringIO()
|
||||||
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
||||||
stdout.seek(0)
|
stdout.seek(0)
|
||||||
output = stdout.readlines()
|
output = stdout.readlines()
|
||||||
|
@ -68,7 +67,7 @@ class TestRevokeAPIKeys(TestCase):
|
||||||
apikey = APIKey.objects.create(
|
apikey = APIKey.objects.create(
|
||||||
key='user:{}:{}'.format(user.pk, '666'), secret=right_secret,
|
key='user:{}:{}'.format(user.pk, '666'), secret=right_secret,
|
||||||
user=user, is_active=True)
|
user=user, is_active=True)
|
||||||
stdout = StringIO()
|
stdout = io.StringIO()
|
||||||
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
||||||
stdout.seek(0)
|
stdout.seek(0)
|
||||||
output = stdout.readlines()
|
output = stdout.readlines()
|
||||||
|
@ -92,7 +91,7 @@ class TestRevokeAPIKeys(TestCase):
|
||||||
apikey = APIKey.objects.create(
|
apikey = APIKey.objects.create(
|
||||||
key='user:{}:{}'.format(user.pk, '333'), secret=right_secret,
|
key='user:{}:{}'.format(user.pk, '333'), secret=right_secret,
|
||||||
user=user, is_active=True)
|
user=user, is_active=True)
|
||||||
stdout = StringIO()
|
stdout = io.StringIO()
|
||||||
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
call_command('revoke_api_keys', self.csv_path, stdout=stdout)
|
||||||
stdout.seek(0)
|
stdout.seek(0)
|
||||||
output = stdout.readlines()
|
output = stdout.readlines()
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -62,12 +60,10 @@ class TestTranslationSerializerField(TestCase):
|
||||||
field.bind('name', serializer)
|
field.bind('name', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = {
|
expected = {
|
||||||
'en-US': six.text_type(
|
'en-US': str(Translation.objects.get(
|
||||||
Translation.objects.get(id=self.addon.name.id,
|
id=self.addon.name.id, locale='en-US')),
|
||||||
locale='en-US')),
|
'es': str(Translation.objects.get(
|
||||||
'es': six.text_type(
|
id=self.addon.name.id, locale='es')),
|
||||||
Translation.objects.get(id=self.addon.name.id,
|
|
||||||
locale='es')),
|
|
||||||
}
|
}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
@ -84,7 +80,7 @@ class TestTranslationSerializerField(TestCase):
|
||||||
field.bind('name', serializer)
|
field.bind('name', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = {
|
expected = {
|
||||||
'en-US': six.text_type(self.addon.name),
|
'en-US': str(self.addon.name),
|
||||||
}
|
}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
@ -92,7 +88,7 @@ class TestTranslationSerializerField(TestCase):
|
||||||
field.bind('description', serializer)
|
field.bind('description', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = {
|
expected = {
|
||||||
'en-US': six.text_type(self.addon.description),
|
'en-US': str(self.addon.description),
|
||||||
}
|
}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
@ -171,12 +167,10 @@ class TestTranslationSerializerField(TestCase):
|
||||||
field = self.field_class(source='mymock.mymocked_field')
|
field = self.field_class(source='mymock.mymocked_field')
|
||||||
result = field.to_internal_value(field.get_attribute(self.addon))
|
result = field.to_internal_value(field.get_attribute(self.addon))
|
||||||
expected = {
|
expected = {
|
||||||
'en-US': six.text_type(
|
'en-US': str(Translation.objects.get(
|
||||||
Translation.objects.get(id=self.addon.name.id,
|
id=self.addon.name.id, locale='en-US')),
|
||||||
locale='en-US')),
|
'es': str(Translation.objects.get(
|
||||||
'es': six.text_type(
|
id=self.addon.name.id, locale='es')),
|
||||||
Translation.objects.get(id=self.addon.name.id,
|
|
||||||
locale='es')),
|
|
||||||
}
|
}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
@ -247,13 +241,13 @@ class TestTranslationSerializerFieldFlat(TestTranslationSerializerField):
|
||||||
def _test_expected_single_locale(self, field, serializer=None):
|
def _test_expected_single_locale(self, field, serializer=None):
|
||||||
field.bind('name', serializer)
|
field.bind('name', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = six.text_type(self.addon.name)
|
expected = str(self.addon.name)
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
field.source = None
|
field.source = None
|
||||||
field.bind('description', serializer)
|
field.bind('description', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = six.text_type(self.addon.description)
|
expected = str(self.addon.description)
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
def test_to_internal_value(self):
|
def test_to_internal_value(self):
|
||||||
|
@ -344,7 +338,7 @@ class TestESTranslationSerializerField(TestTranslationSerializerField):
|
||||||
field.bind('name', serializer)
|
field.bind('name', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = {
|
expected = {
|
||||||
'en-US': six.text_type(self.addon.name_translations['en-US'])
|
'en-US': str(self.addon.name_translations['en-US'])
|
||||||
}
|
}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
@ -352,8 +346,7 @@ class TestESTranslationSerializerField(TestTranslationSerializerField):
|
||||||
field.bind('description', serializer)
|
field.bind('description', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = {
|
expected = {
|
||||||
'en-US': six.text_type(
|
'en-US': str(self.addon.description_translations['en-US'])
|
||||||
self.addon.description_translations['en-US'])
|
|
||||||
}
|
}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
@ -397,13 +390,13 @@ class TestESTranslationSerializerFieldFlat(TestTranslationSerializerFieldFlat,
|
||||||
def _test_expected_single_locale(self, field, serializer=None):
|
def _test_expected_single_locale(self, field, serializer=None):
|
||||||
field.bind('name', serializer)
|
field.bind('name', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = six.text_type(self.addon.name_translations['en-US'])
|
expected = str(self.addon.name_translations['en-US'])
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
field.source = None
|
field.source = None
|
||||||
field.bind('description', serializer)
|
field.bind('description', serializer)
|
||||||
result = field.to_representation(field.get_attribute(self.addon))
|
result = field.to_representation(field.get_attribute(self.addon))
|
||||||
expected = six.text_type(self.addon.description_translations['en-US'])
|
expected = str(self.addon.description_translations['en-US'])
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import io
|
||||||
|
|
||||||
from gzip import GzipFile
|
from gzip import GzipFile
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
from six import BytesIO
|
|
||||||
|
|
||||||
from olympia.amo.tests import TestCase, addon_factory, reverse_ns
|
from olympia.amo.tests import TestCase, addon_factory, reverse_ns
|
||||||
from olympia.api.middleware import (
|
from olympia.api.middleware import (
|
||||||
GZipMiddlewareForAPIOnly, IdentifyAPIRequestMiddleware)
|
GZipMiddlewareForAPIOnly, IdentifyAPIRequestMiddleware)
|
||||||
|
@ -77,5 +77,5 @@ class TestGzipMiddleware(TestCase):
|
||||||
|
|
||||||
assert len(response_gzipped.content) < len(response.content)
|
assert len(response_gzipped.content) < len(response.content)
|
||||||
ungzipped_content = GzipFile(
|
ungzipped_content = GzipFile(
|
||||||
'', 'r', 0, BytesIO(response_gzipped.content)).read()
|
'', 'r', 0, io.BytesIO(response_gzipped.content)).read()
|
||||||
assert ungzipped_content == response.content
|
assert ungzipped_content == response.content
|
||||||
|
|
|
@ -2,8 +2,6 @@ from unittest import mock
|
||||||
|
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
|
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
from olympia.amo.tests import TestCase
|
from olympia.amo.tests import TestCase
|
||||||
from olympia.users.models import UserProfile
|
from olympia.users.models import UserProfile
|
||||||
|
|
||||||
|
@ -27,10 +25,10 @@ class TestAPIKey(TestCase):
|
||||||
|
|
||||||
def test_string_representation(self):
|
def test_string_representation(self):
|
||||||
credentials = APIKey.new_jwt_credentials(self.user)
|
credentials = APIKey.new_jwt_credentials(self.user)
|
||||||
str_creds = text_type(credentials)
|
str_creds = str(credentials)
|
||||||
assert credentials.key in str_creds
|
assert credentials.key in str_creds
|
||||||
assert credentials.secret not in str_creds
|
assert credentials.secret not in str_creds
|
||||||
assert text_type(credentials.user) in str_creds
|
assert str(credentials.user) in str_creds
|
||||||
|
|
||||||
def test_cant_have_two_active_keys_for_same_user(self):
|
def test_cant_have_two_active_keys_for_same_user(self):
|
||||||
APIKey.new_jwt_credentials(self.user)
|
APIKey.new_jwt_credentials(self.user)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from rest_framework.test import APIClient
|
from rest_framework.test import APIClient
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
from olympia.amo.tests import TestCase
|
from olympia.amo.tests import TestCase
|
||||||
from olympia.api.authentication import JWTKeyAuthentication
|
from olympia.api.authentication import JWTKeyAuthentication
|
||||||
|
@ -19,7 +18,7 @@ class APIKeyAuthTestMixin(TestCase, JWTAuthKeyTester):
|
||||||
read_dev_agreement=datetime.today(),
|
read_dev_agreement=datetime.today(),
|
||||||
)
|
)
|
||||||
self.api_key = self.create_api_key(
|
self.api_key = self.create_api_key(
|
||||||
self.user, text_type(self.user.pk) + ':f')
|
self.user, str(self.user.pk) + ':f')
|
||||||
|
|
||||||
def authorization(self):
|
def authorization(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
|
|
||||||
from olympia.amo.fields import PositiveAutoField
|
from olympia.amo.fields import PositiveAutoField
|
||||||
from olympia.amo.models import ModelBase
|
from olympia.amo.models import ModelBase
|
||||||
|
@ -7,7 +6,6 @@ from olympia.constants.applications import APPS_CHOICES
|
||||||
from olympia.versions import compare
|
from olympia.versions import compare
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class AppVersion(ModelBase):
|
class AppVersion(ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
application = models.PositiveIntegerField(choices=APPS_CHOICES,
|
application = models.PositiveIntegerField(choices=APPS_CHOICES,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
|
|
||||||
from olympia import activity, amo
|
from olympia import activity, amo
|
||||||
from olympia.access import acl
|
from olympia.access import acl
|
||||||
|
@ -61,7 +60,6 @@ class CollectionManager(ManagerBase):
|
||||||
return self.filter(author=user.pk)
|
return self.filter(author=user.pk)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Collection(ModelBase):
|
class Collection(ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
TYPE_CHOICES = amo.COLLECTION_CHOICES.items()
|
TYPE_CHOICES = amo.COLLECTION_CHOICES.items()
|
||||||
|
@ -279,7 +277,6 @@ models.signals.post_delete.connect(CollectionAddon.post_delete,
|
||||||
dispatch_uid='coll.post_delete')
|
dispatch_uid='coll.post_delete')
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class FeaturedCollection(ModelBase):
|
class FeaturedCollection(ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
application = models.PositiveIntegerField(choices=amo.APPS_CHOICES,
|
application = models.PositiveIntegerField(choices=amo.APPS_CHOICES,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.core.serializers import serialize as object_serialize
|
from django.core.serializers import serialize as object_serialize
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
@ -88,7 +87,7 @@ class CollectionSerializer(serializers.ModelSerializer):
|
||||||
# if we have a localised dict of values validate them all.
|
# if we have a localised dict of values validate them all.
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
return {locale: self.validate_name(sub_value)
|
return {locale: self.validate_name(sub_value)
|
||||||
for locale, sub_value in six.iteritems(value)}
|
for locale, sub_value in value.items()}
|
||||||
if value.strip() == u'':
|
if value.strip() == u'':
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
ugettext(u'Name cannot be empty.'))
|
ugettext(u'Name cannot be empty.'))
|
||||||
|
@ -98,7 +97,7 @@ class CollectionSerializer(serializers.ModelSerializer):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def validate_description(self, value):
|
def validate_description(self, value):
|
||||||
if has_links(clean_nl(six.text_type(value))):
|
if has_links(clean_nl(str(value))):
|
||||||
# There's some links, we don't want them.
|
# There's some links, we don't want them.
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
ugettext(u'No links are allowed.'))
|
ugettext(u'No links are allowed.'))
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
@ -94,7 +92,7 @@ class TestCollectionAdmin(TestCase):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode('utf-8')
|
||||||
assert collection.slug in content
|
assert collection.slug in content
|
||||||
assert six.text_type(addon.name) in content
|
assert str(addon.name) in content
|
||||||
|
|
||||||
post_data = {
|
post_data = {
|
||||||
# Django wants the whole form to be submitted, unfortunately.
|
# Django wants the whole form to be submitted, unfortunately.
|
||||||
|
@ -199,7 +197,7 @@ class TestCollectionAdmin(TestCase):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode('utf-8')
|
||||||
assert collection.slug in content
|
assert collection.slug in content
|
||||||
assert six.text_type(addon.name) in content
|
assert str(addon.name) in content
|
||||||
|
|
||||||
post_data = {
|
post_data = {
|
||||||
# Django wants the whole form to be submitted, unfortunately.
|
# Django wants the whole form to be submitted, unfortunately.
|
||||||
|
@ -230,7 +228,7 @@ class TestCollectionAdmin(TestCase):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode('utf-8')
|
||||||
assert collection.slug in content
|
assert collection.slug in content
|
||||||
assert six.text_type(addon2.name) in content
|
assert str(addon2.name) in content
|
||||||
assert CollectionAddon.objects.filter(
|
assert CollectionAddon.objects.filter(
|
||||||
collection=collection).count() == 1
|
collection=collection).count() == 1
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo, core
|
from olympia import amo, core
|
||||||
from olympia.activity.models import ActivityLog
|
from olympia.activity.models import ActivityLog
|
||||||
|
@ -38,13 +37,12 @@ class TestCollections(TestCase):
|
||||||
description='<a href="http://example.com">example.com</a> '
|
description='<a href="http://example.com">example.com</a> '
|
||||||
'http://example.com <b>foo</b> some text')
|
'http://example.com <b>foo</b> some text')
|
||||||
# All markup escaped, links are stripped.
|
# All markup escaped, links are stripped.
|
||||||
assert six.text_type(
|
assert str(c.description) == '<b>foo</b> some text'
|
||||||
c.description) == '<b>foo</b> some text'
|
|
||||||
|
|
||||||
def test_translation_default(self):
|
def test_translation_default(self):
|
||||||
"""Make sure we're getting strings from the default locale."""
|
"""Make sure we're getting strings from the default locale."""
|
||||||
c = Collection.objects.get(pk=512)
|
c = Collection.objects.get(pk=512)
|
||||||
assert six.text_type(c.name) == 'yay'
|
assert str(c.name) == 'yay'
|
||||||
|
|
||||||
def test_listed(self):
|
def test_listed(self):
|
||||||
"""Make sure the manager's listed() filter works."""
|
"""Make sure the manager's listed() filter works."""
|
||||||
|
|
|
@ -6,8 +6,6 @@ import django.test
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from rest_framework.fields import empty
|
from rest_framework.fields import empty
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
@ -239,7 +237,7 @@ class TestCollectionViewSetDetail(TestCase):
|
||||||
addon_data = response.data['addons'][0]['addon']
|
addon_data = response.data['addons'][0]['addon']
|
||||||
assert addon_data['id'] == addon.id
|
assert addon_data['id'] == addon.id
|
||||||
assert isinstance(addon_data['name'], dict)
|
assert isinstance(addon_data['name'], dict)
|
||||||
assert addon_data['name'] == {'en-US': six.text_type(addon.name)}
|
assert addon_data['name'] == {'en-US': str(addon.name)}
|
||||||
|
|
||||||
# Now test the limit of addons returned
|
# Now test the limit of addons returned
|
||||||
self.collection.add_addon(addon_factory())
|
self.collection.add_addon(addon_factory())
|
||||||
|
@ -264,14 +262,14 @@ class TestCollectionViewSetDetail(TestCase):
|
||||||
assert response.data['id'] == self.collection.id
|
assert response.data['id'] == self.collection.id
|
||||||
addon_data = response.data['addons'][0]['addon']
|
addon_data = response.data['addons'][0]['addon']
|
||||||
assert addon_data['id'] == addon.id
|
assert addon_data['id'] == addon.id
|
||||||
assert isinstance(addon_data['name']['en-US'], six.string_types)
|
assert isinstance(addon_data['name']['en-US'], str)
|
||||||
assert addon_data['name'] == {'en-US': six.text_type(addon.name)}
|
assert addon_data['name'] == {'en-US': str(addon.name)}
|
||||||
assert isinstance(addon_data['homepage']['en-US'], six.string_types)
|
assert isinstance(addon_data['homepage']['en-US'], str)
|
||||||
assert addon_data['homepage'] == {
|
assert addon_data['homepage'] == {
|
||||||
'en-US': get_outgoing_url(six.text_type(addon.homepage))}
|
'en-US': get_outgoing_url(str(addon.homepage))}
|
||||||
assert isinstance(addon_data['support_url']['en-US'], six.string_types)
|
assert isinstance(addon_data['support_url']['en-US'], str)
|
||||||
assert addon_data['support_url'] == {
|
assert addon_data['support_url'] == {
|
||||||
'en-US': get_outgoing_url(six.text_type(addon.support_url))}
|
'en-US': get_outgoing_url(str(addon.support_url))}
|
||||||
|
|
||||||
overridden_api_gates = {
|
overridden_api_gates = {
|
||||||
'v5': ('l10n_flat_input_output',)}
|
'v5': ('l10n_flat_input_output',)}
|
||||||
|
@ -282,14 +280,14 @@ class TestCollectionViewSetDetail(TestCase):
|
||||||
assert response.data['id'] == self.collection.id
|
assert response.data['id'] == self.collection.id
|
||||||
addon_data = response.data['addons'][0]['addon']
|
addon_data = response.data['addons'][0]['addon']
|
||||||
assert addon_data['id'] == addon.id
|
assert addon_data['id'] == addon.id
|
||||||
assert isinstance(addon_data['name'], six.string_types)
|
assert isinstance(addon_data['name'], str)
|
||||||
assert addon_data['name'] == six.text_type(addon.name)
|
assert addon_data['name'] == str(addon.name)
|
||||||
assert isinstance(addon_data['homepage'], six.string_types)
|
assert isinstance(addon_data['homepage'], str)
|
||||||
assert addon_data['homepage'] == get_outgoing_url(
|
assert addon_data['homepage'] == get_outgoing_url(
|
||||||
six.text_type(addon.homepage))
|
str(addon.homepage))
|
||||||
assert isinstance(addon_data['support_url'], six.string_types)
|
assert isinstance(addon_data['support_url'], str)
|
||||||
assert addon_data['support_url'] == get_outgoing_url(
|
assert addon_data['support_url'] == get_outgoing_url(
|
||||||
six.text_type(addon.support_url))
|
str(addon.support_url))
|
||||||
|
|
||||||
|
|
||||||
class CollectionViewSetDataMixin(object):
|
class CollectionViewSetDataMixin(object):
|
||||||
|
@ -319,7 +317,7 @@ class CollectionViewSetDataMixin(object):
|
||||||
return self._user
|
return self._user
|
||||||
|
|
||||||
def check_data(self, collection, data, json):
|
def check_data(self, collection, data, json):
|
||||||
for prop, value in six.iteritems(data):
|
for prop, value in data.items():
|
||||||
assert json[prop] == value
|
assert json[prop] == value
|
||||||
|
|
||||||
with self.activate('fr'):
|
with self.activate('fr'):
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import waffle
|
import waffle
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
from olympia.lib.akismet.models import AkismetReport
|
from olympia.lib.akismet.models import AkismetReport
|
||||||
from olympia.translations.models import Translation
|
from olympia.translations.models import Translation
|
||||||
|
@ -18,7 +17,7 @@ def get_collection_akismet_reports(collection, user, user_agent, referrer,
|
||||||
translation_ids = [id_ for id_ in translation_ids_gen if id_]
|
translation_ids = [id_ for id_ in translation_ids_gen if id_]
|
||||||
# Just get all the values together to make it simplier
|
# Just get all the values together to make it simplier
|
||||||
existing_data = {
|
existing_data = {
|
||||||
text_type(value)
|
str(value)
|
||||||
for value in Translation.objects.filter(id__in=translation_ids)}
|
for value in Translation.objects.filter(id__in=translation_ids)}
|
||||||
reports = []
|
reports = []
|
||||||
for prop in properties:
|
for prop in properties:
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
@ -129,7 +127,7 @@ class CollectionAddonViewSet(ModelViewSet):
|
||||||
self.lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
|
self.lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
|
||||||
lookup_value = self.kwargs.get(self.lookup_url_kwarg)
|
lookup_value = self.kwargs.get(self.lookup_url_kwarg)
|
||||||
# if the lookup is not a number, its probably the slug instead.
|
# if the lookup is not a number, its probably the slug instead.
|
||||||
if lookup_value and not six.text_type(lookup_value).isdigit():
|
if lookup_value and not str(lookup_value).isdigit():
|
||||||
self.lookup_field = '%s__slug' % self.lookup_field
|
self.lookup_field = '%s__slug' % self.lookup_field
|
||||||
return super(CollectionAddonViewSet, self).get_object()
|
return super(CollectionAddonViewSet, self).get_object()
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,9 @@ import copy
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import force_bytes, python_2_unicode_compatible
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.constants.applications import ANDROID, FIREFOX
|
from olympia.constants.applications import ANDROID, FIREFOX
|
||||||
from olympia.constants.base import (
|
from olympia.constants.base import (
|
||||||
ADDON_DICT, ADDON_EXTENSION, ADDON_LPAPP, ADDON_PERSONA, ADDON_SEARCH,
|
ADDON_DICT, ADDON_EXTENSION, ADDON_LPAPP, ADDON_PERSONA, ADDON_SEARCH,
|
||||||
|
@ -16,7 +14,6 @@ from olympia.constants.base import (
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
@python_2_unicode_compatible
|
|
||||||
class StaticCategory(object):
|
class StaticCategory(object):
|
||||||
"""Helper to populate `CATEGORIES` and provide some helpers.
|
"""Helper to populate `CATEGORIES` and provide some helpers.
|
||||||
|
|
||||||
|
@ -33,7 +30,7 @@ class StaticCategory(object):
|
||||||
object.__setattr__(self, 'description', description)
|
object.__setattr__(self, 'description', description)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self.name)
|
return str(self.name)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s (%s)>' % (
|
return '<%s: %s (%s)>' % (
|
||||||
|
|
|
@ -3,6 +3,8 @@ import os
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.storage import default_storage as storage
|
from django.core.files.storage import default_storage as storage
|
||||||
|
@ -15,11 +17,9 @@ from django.utils.encoding import force_text
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _, ungettext
|
from django.utils.translation import ugettext, ugettext_lazy as _, ungettext
|
||||||
|
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from rest_framework.exceptions import Throttled
|
from rest_framework.exceptions import Throttled
|
||||||
from six.moves.urllib_parse import urlsplit
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.access import acl
|
from olympia.access import acl
|
||||||
|
@ -525,11 +525,10 @@ class LicenseRadioSelect(forms.RadioSelect):
|
||||||
|
|
||||||
if hasattr(license, 'url') and license.url:
|
if hasattr(license, 'url') and license.url:
|
||||||
details = link % (license.url, ugettext('Details'))
|
details = link % (license.url, ugettext('Details'))
|
||||||
context['label'] = mark_safe(
|
context['label'] = mark_safe(str(context['label']) + ' ' + details)
|
||||||
six.text_type(context['label']) + ' ' + details)
|
|
||||||
if hasattr(license, 'icons'):
|
if hasattr(license, 'icons'):
|
||||||
context['attrs']['data-cc'] = license.icons
|
context['attrs']['data-cc'] = license.icons
|
||||||
context['attrs']['data-name'] = six.text_type(license)
|
context['attrs']['data-name'] = str(license)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -874,7 +873,7 @@ class BaseCompatFormSet(BaseModelFormSet):
|
||||||
# hidden delete fields in the data attribute, cause that's used to
|
# hidden delete fields in the data attribute, cause that's used to
|
||||||
# populate initial data for all forms, and would therefore make
|
# populate initial data for all forms, and would therefore make
|
||||||
# those delete fields active again.
|
# those delete fields active again.
|
||||||
self.data = {k: v for k, v in six.iteritems(self.data)
|
self.data = {k: v for k, v in self.data.items()
|
||||||
if not k.endswith('-DELETE')}
|
if not k.endswith('-DELETE')}
|
||||||
for form in self.forms:
|
for form in self.forms:
|
||||||
form.data = self.data
|
form.data = self.data
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from urllib.parse import unquote_to_bytes
|
||||||
|
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.translation import ugettext, ungettext
|
from django.utils.translation import ugettext, ungettext
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
import six
|
|
||||||
|
|
||||||
from django_jinja import library
|
from django_jinja import library
|
||||||
from six.moves.urllib.parse import unquote_to_bytes
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.access import acl
|
from olympia.access import acl
|
||||||
|
@ -71,7 +70,7 @@ def dev_files_status(files):
|
||||||
for file in files:
|
for file in files:
|
||||||
status_count[file.status] += 1
|
status_count[file.status] += 1
|
||||||
|
|
||||||
return [(count, six.text_type(choices[status])) for
|
return [(count, str(choices[status])) for
|
||||||
(status, count) in status_count.items()]
|
(status, count) in status_count.items()]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.utils.encoding import force_text
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import six
|
from django.utils.encoding import force_text
|
||||||
from six.moves.urllib_parse import urlencode
|
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
|
|
||||||
|
@ -231,8 +230,8 @@ class TestActivity(HubTest):
|
||||||
self.log_creates(1)
|
self.log_creates(1)
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 1
|
assert len(doc('.item')) == 1
|
||||||
assert '<script>' not in six.text_type(doc), 'XSS FTL'
|
assert '<script>' not in str(doc), 'XSS FTL'
|
||||||
assert '<script>' in six.text_type(doc), 'XSS FTL'
|
assert '<script>' in str(doc), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_unlisted_addon(self):
|
def test_xss_unlisted_addon(self):
|
||||||
self.addon.name = ("<script>alert('Buy more Diet Mountain Dew.')"
|
self.addon.name = ("<script>alert('Buy more Diet Mountain Dew.')"
|
||||||
|
@ -242,53 +241,53 @@ class TestActivity(HubTest):
|
||||||
self.log_creates(1)
|
self.log_creates(1)
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 2
|
assert len(doc('.item')) == 2
|
||||||
assert '<script>' not in six.text_type(doc), 'XSS FTL'
|
assert '<script>' not in str(doc), 'XSS FTL'
|
||||||
assert '<script>' in six.text_type(doc), 'XSS FTL'
|
assert '<script>' in str(doc), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_collections(self):
|
def test_xss_collections(self):
|
||||||
self.log_collection(1, "<script>alert('v1@gra for u')</script>")
|
self.log_collection(1, "<script>alert('v1@gra for u')</script>")
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 1
|
assert len(doc('.item')) == 1
|
||||||
assert '<script>' not in six.text_type(doc), 'XSS FTL'
|
assert '<script>' not in str(doc), 'XSS FTL'
|
||||||
assert '<script>' in six.text_type(doc), 'XSS FTL'
|
assert '<script>' in str(doc), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_collections_unlisted_addon(self):
|
def test_xss_collections_unlisted_addon(self):
|
||||||
self.make_addon_unlisted(self.addon)
|
self.make_addon_unlisted(self.addon)
|
||||||
self.log_collection(1, "<script>alert('v1@gra for u')</script>")
|
self.log_collection(1, "<script>alert('v1@gra for u')</script>")
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 2
|
assert len(doc('.item')) == 2
|
||||||
assert '<script>' not in six.text_type(doc), 'XSS FTL'
|
assert '<script>' not in str(doc), 'XSS FTL'
|
||||||
assert '<script>' in six.text_type(doc), 'XSS FTL'
|
assert '<script>' in str(doc), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_tags(self):
|
def test_xss_tags(self):
|
||||||
self.log_tag(1, "<script src='x.js'>")
|
self.log_tag(1, "<script src='x.js'>")
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 1
|
assert len(doc('.item')) == 1
|
||||||
assert '<script' not in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' not in str(doc('.item')), 'XSS FTL'
|
||||||
assert '<script' in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' in str(doc('.item')), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_tags_unlisted_addon(self):
|
def test_xss_tags_unlisted_addon(self):
|
||||||
self.make_addon_unlisted(self.addon)
|
self.make_addon_unlisted(self.addon)
|
||||||
self.log_tag(1, "<script src='x.js'>")
|
self.log_tag(1, "<script src='x.js'>")
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 2
|
assert len(doc('.item')) == 2
|
||||||
assert '<script' not in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' not in str(doc('.item')), 'XSS FTL'
|
||||||
assert '<script' in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' in str(doc('.item')), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_versions(self):
|
def test_xss_versions(self):
|
||||||
self.log_updates(1, "<script src='x.js'>")
|
self.log_updates(1, "<script src='x.js'>")
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 1
|
assert len(doc('.item')) == 1
|
||||||
assert '<script' not in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' not in str(doc('.item')), 'XSS FTL'
|
||||||
assert '<script' in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' in str(doc('.item')), 'XSS FTL'
|
||||||
|
|
||||||
def test_xss_versions_unlisted_addon(self):
|
def test_xss_versions_unlisted_addon(self):
|
||||||
self.make_addon_unlisted(self.addon)
|
self.make_addon_unlisted(self.addon)
|
||||||
self.log_updates(1, "<script src='x.js'>")
|
self.log_updates(1, "<script src='x.js'>")
|
||||||
doc = self.get_pq()
|
doc = self.get_pq()
|
||||||
assert len(doc('.item')) == 2
|
assert len(doc('.item')) == 2
|
||||||
assert '<script' not in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' not in str(doc('.item')), 'XSS FTL'
|
||||||
assert '<script' in six.text_type(doc('.item')), 'XSS FTL'
|
assert '<script' in str(doc('.item')), 'XSS FTL'
|
||||||
|
|
||||||
def test_hidden(self):
|
def test_hidden(self):
|
||||||
version = Version.objects.create(addon=self.addon)
|
version = Version.objects.create(addon=self.addon)
|
||||||
|
|
|
@ -3,15 +3,14 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.storage import default_storage as storage
|
from django.core.files.storage import default_storage as storage
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
|
||||||
|
@ -330,7 +329,7 @@ class TestDistributionChoiceForm(TestCase):
|
||||||
label = form.fields['channel'].choices[0][1]
|
label = form.fields['channel'].choices[0][1]
|
||||||
|
|
||||||
expected = 'On this site.'
|
expected = 'On this site.'
|
||||||
label = six.text_type(label)
|
label = str(label)
|
||||||
assert label.startswith(expected)
|
assert label.startswith(expected)
|
||||||
|
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
|
@ -338,7 +337,7 @@ class TestDistributionChoiceForm(TestCase):
|
||||||
label = form.fields['channel'].choices[0][1]
|
label = form.fields['channel'].choices[0][1]
|
||||||
|
|
||||||
expected = 'Auf dieser Website.'
|
expected = 'Auf dieser Website.'
|
||||||
label = six.text_type(label)
|
label = str(label)
|
||||||
assert label.startswith(expected)
|
assert label.startswith(expected)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.encoding import force_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
from six.moves.urllib.parse import quote
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.activity.models import ActivityLog
|
from olympia.activity.models import ActivityLog
|
||||||
|
@ -60,7 +60,7 @@ def test_summarize_validation():
|
||||||
|
|
||||||
def test_log_action_class():
|
def test_log_action_class():
|
||||||
v = Mock()
|
v = Mock()
|
||||||
for k, v in six.iteritems(amo.LOG_BY_ID):
|
for k, v in amo.LOG_BY_ID.items():
|
||||||
if v.action_class is not None:
|
if v.action_class is not None:
|
||||||
cls = 'action-' + v.action_class
|
cls = 'action-' + v.action_class
|
||||||
else:
|
else:
|
||||||
|
@ -99,7 +99,7 @@ class TestDevFilesStatus(TestCase):
|
||||||
def expect(self, expected):
|
def expect(self, expected):
|
||||||
cnt, msg = jinja_helpers.dev_files_status([self.file])[0]
|
cnt, msg = jinja_helpers.dev_files_status([self.file])[0]
|
||||||
assert cnt == 1
|
assert cnt == 1
|
||||||
assert msg == six.text_type(expected)
|
assert msg == str(expected)
|
||||||
|
|
||||||
def test_unreviewed_public(self):
|
def test_unreviewed_public(self):
|
||||||
self.addon.status = amo.STATUS_APPROVED
|
self.addon.status = amo.STATUS_APPROVED
|
||||||
|
|
|
@ -11,7 +11,6 @@ import pytest
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
|
||||||
from celery.result import AsyncResult
|
from celery.result import AsyncResult
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.amo.storage_utils import copy_stored_file
|
from olympia.amo.storage_utils import copy_stored_file
|
||||||
|
@ -334,7 +333,7 @@ class TestGetAddonAkismetReports(UploadTest, TestCase):
|
||||||
existing_data = utils.fetch_existing_translations_from_addon(
|
existing_data = utils.fetch_existing_translations_from_addon(
|
||||||
addon, ('summary', 'name', 'description'))
|
addon, ('summary', 'name', 'description'))
|
||||||
# check fetch_existing_translations_from_addon worked okay
|
# check fetch_existing_translations_from_addon worked okay
|
||||||
assert existing_data == {text_type(addon.name), u'¡Ochó!'}
|
assert existing_data == {str(addon.name), u'¡Ochó!'}
|
||||||
self.parse_addon_mock.return_value = {
|
self.parse_addon_mock.return_value = {
|
||||||
'description': {
|
'description': {
|
||||||
'en-US': u'fóó',
|
'en-US': u'fóó',
|
||||||
|
@ -373,7 +372,7 @@ class TestGetAddonAkismetReports(UploadTest, TestCase):
|
||||||
existing_data = utils.fetch_existing_translations_from_addon(
|
existing_data = utils.fetch_existing_translations_from_addon(
|
||||||
addon, ('summary', 'name', 'description'))
|
addon, ('summary', 'name', 'description'))
|
||||||
# check fetch_existing_translations_from_addon worked okay
|
# check fetch_existing_translations_from_addon worked okay
|
||||||
assert existing_data == {text_type(addon.name), u'¡Ochó!'}
|
assert existing_data == {str(addon.name), u'¡Ochó!'}
|
||||||
cleaned_data = {
|
cleaned_data = {
|
||||||
'description': {
|
'description': {
|
||||||
'en-US': u'fóó',
|
'en-US': u'fóó',
|
||||||
|
|
|
@ -3,6 +3,7 @@ import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
@ -17,7 +18,6 @@ import pytest
|
||||||
import responses
|
import responses
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from six.moves.urllib_parse import urlencode
|
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
|
||||||
from olympia import amo, core
|
from olympia import amo, core
|
||||||
|
|
|
@ -7,7 +7,6 @@ from django.core.files.storage import default_storage as storage
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
@ -116,15 +115,15 @@ class BaseTestEditDescribe(BaseTestEdit):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
assert six.text_type(addon.name) == data['name']
|
assert str(addon.name) == data['name']
|
||||||
assert addon.name.id == old_name.id
|
assert addon.name.id == old_name.id
|
||||||
|
|
||||||
assert six.text_type(addon.summary) == data['summary']
|
assert str(addon.summary) == data['summary']
|
||||||
assert six.text_type(addon.slug) == data['slug']
|
assert str(addon.slug) == data['slug']
|
||||||
|
|
||||||
if self.listed:
|
if self.listed:
|
||||||
assert (
|
assert (
|
||||||
[six.text_type(t) for t in addon.tags.all()] ==
|
[str(t) for t in addon.tags.all()] ==
|
||||||
sorted(self.tags))
|
sorted(self.tags))
|
||||||
|
|
||||||
def test_edit_slug_invalid(self):
|
def test_edit_slug_invalid(self):
|
||||||
|
@ -175,13 +174,13 @@ class BaseTestEditDescribe(BaseTestEdit):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
assert six.text_type(addon.name) == data['name']
|
assert str(addon.name) == data['name']
|
||||||
assert six.text_type(addon.summary) == data['summary']
|
assert str(addon.summary) == data['summary']
|
||||||
assert six.text_type(addon.slug) == data['slug']
|
assert str(addon.slug) == data['slug']
|
||||||
|
|
||||||
if self.listed:
|
if self.listed:
|
||||||
assert (
|
assert (
|
||||||
[six.text_type(t) for t in addon.tags.all()] ==
|
[str(t) for t in addon.tags.all()] ==
|
||||||
sorted(self.tags))
|
sorted(self.tags))
|
||||||
|
|
||||||
def test_edit_name_required(self):
|
def test_edit_name_required(self):
|
||||||
|
@ -297,7 +296,7 @@ class BaseTestEditDescribe(BaseTestEdit):
|
||||||
|
|
||||||
response = self.client.get(self.url)
|
response = self.client.get(self.url)
|
||||||
doc_links = [
|
doc_links = [
|
||||||
six.text_type(a.attrib['href'])
|
str(a.attrib['href'])
|
||||||
for a in pq(response.content)('#edit-addon-nav').find('li a')]
|
for a in pq(response.content)('#edit-addon-nav').find('li a')]
|
||||||
assert links == doc_links
|
assert links == doc_links
|
||||||
|
|
||||||
|
@ -348,9 +347,9 @@ class BaseTestEditDescribe(BaseTestEdit):
|
||||||
|
|
||||||
# And metadata was updated
|
# And metadata was updated
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
assert six.text_type(addon.name) == data['name']
|
assert str(addon.name) == data['name']
|
||||||
assert six.text_type(addon.summary) == data['summary']
|
assert str(addon.summary) == data['summary']
|
||||||
assert six.text_type(addon.description) == data['description']
|
assert str(addon.description) == data['description']
|
||||||
|
|
||||||
@override_switch('akismet-spam-check', active=True)
|
@override_switch('akismet-spam-check', active=True)
|
||||||
@override_switch('akismet-addon-action', active=False)
|
@override_switch('akismet-addon-action', active=False)
|
||||||
|
@ -380,9 +379,9 @@ class BaseTestEditDescribe(BaseTestEdit):
|
||||||
|
|
||||||
# And metadata was updated
|
# And metadata was updated
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
assert six.text_type(addon.name) == data['name']
|
assert str(addon.name) == data['name']
|
||||||
assert six.text_type(addon.summary) == data['summary']
|
assert str(addon.summary) == data['summary']
|
||||||
assert six.text_type(addon.description) == data['description']
|
assert str(addon.description) == data['description']
|
||||||
|
|
||||||
@override_switch('akismet-spam-check', active=True)
|
@override_switch('akismet-spam-check', active=True)
|
||||||
@override_switch('akismet-addon-action', active=True)
|
@override_switch('akismet-addon-action', active=True)
|
||||||
|
@ -422,10 +421,9 @@ class BaseTestEditDescribe(BaseTestEdit):
|
||||||
|
|
||||||
# And metadata was NOT updated
|
# And metadata was NOT updated
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
assert six.text_type(addon.name) == six.text_type(old_name)
|
assert str(addon.name) == str(old_name)
|
||||||
assert six.text_type(addon.summary) == six.text_type(old_summary)
|
assert str(addon.summary) == str(old_summary)
|
||||||
assert six.text_type(
|
assert str(addon.description) == str(old_description)
|
||||||
addon.description) == six.text_type(old_description)
|
|
||||||
|
|
||||||
def test_edit_xss(self):
|
def test_edit_xss(self):
|
||||||
"""
|
"""
|
||||||
|
@ -602,7 +600,7 @@ class TestEditDescribeListed(BaseTestEditDescribe, L10nTestsMixin):
|
||||||
self.cat_initial['categories'] = [22, 1]
|
self.cat_initial['categories'] = [22, 1]
|
||||||
data = self.get_dict()
|
data = self.get_dict()
|
||||||
self.client.post(self.describe_edit_url, data)
|
self.client.post(self.describe_edit_url, data)
|
||||||
assert six.text_type(self.get_addon().name) == data['name']
|
assert str(self.get_addon().name) == data['name']
|
||||||
|
|
||||||
def test_edit_categories_no_disclaimer(self):
|
def test_edit_categories_no_disclaimer(self):
|
||||||
"""Ensure that there is a not disclaimer for non-creatured add-ons."""
|
"""Ensure that there is a not disclaimer for non-creatured add-ons."""
|
||||||
|
@ -745,7 +743,7 @@ class TestEditDescribeListed(BaseTestEditDescribe, L10nTestsMixin):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
def test_edit_support_optional_url(self):
|
def test_edit_support_optional_url(self):
|
||||||
data = {
|
data = {
|
||||||
|
@ -757,7 +755,7 @@ class TestEditDescribeListed(BaseTestEditDescribe, L10nTestsMixin):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
def test_edit_support_optional_email(self):
|
def test_edit_support_optional_email(self):
|
||||||
data = {
|
data = {
|
||||||
|
@ -769,7 +767,7 @@ class TestEditDescribeListed(BaseTestEditDescribe, L10nTestsMixin):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
@override_switch('content-optimization', active=True)
|
@override_switch('content-optimization', active=True)
|
||||||
def test_description_not_optional(self):
|
def test_description_not_optional(self):
|
||||||
|
@ -875,7 +873,7 @@ class TestEditMedia(BaseTestEdit):
|
||||||
assert addon.get_icon_url(64).endswith('icons/default-64.png')
|
assert addon.get_icon_url(64).endswith('icons/default-64.png')
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
def test_edit_media_shows_proper_labels(self):
|
def test_edit_media_shows_proper_labels(self):
|
||||||
"""Regression test for
|
"""Regression test for
|
||||||
|
@ -920,7 +918,7 @@ class TestEditMedia(BaseTestEdit):
|
||||||
assert addon.get_icon_url(64).endswith('icons/appearance-64.png')
|
assert addon.get_icon_url(64).endswith('icons/appearance-64.png')
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
def test_edit_media_uploadedicon(self):
|
def test_edit_media_uploadedicon(self):
|
||||||
img = get_image_path('mozilla.png')
|
img = get_image_path('mozilla.png')
|
||||||
|
@ -1449,7 +1447,7 @@ class BaseTestEditAdditionalDetails(BaseTestEdit):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
def test_edit_homepage_optional(self):
|
def test_edit_homepage_optional(self):
|
||||||
data = {
|
data = {
|
||||||
|
@ -1463,7 +1461,7 @@ class BaseTestEditAdditionalDetails(BaseTestEdit):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
|
|
||||||
for k in data:
|
for k in data:
|
||||||
assert six.text_type(getattr(addon, k)) == data[k]
|
assert str(getattr(addon, k)) == data[k]
|
||||||
|
|
||||||
|
|
||||||
class TestEditAdditionalDetailsListed(BaseTestEditAdditionalDetails,
|
class TestEditAdditionalDetailsListed(BaseTestEditAdditionalDetails,
|
||||||
|
@ -1477,7 +1475,7 @@ class TestEditAdditionalDetailsListed(BaseTestEditAdditionalDetails,
|
||||||
'You are missing ')
|
'You are missing ')
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'homepage': six.text_type(self.addon.homepage),
|
'homepage': str(self.addon.homepage),
|
||||||
'default_locale': 'fr'
|
'default_locale': 'fr'
|
||||||
}
|
}
|
||||||
response = self.client.post(self.details_edit_url, data)
|
response = self.client.post(self.details_edit_url, data)
|
||||||
|
@ -1568,11 +1566,9 @@ class TestEditTechnical(BaseTestEdit):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
for k in data:
|
for k in data:
|
||||||
if k == 'developer_comments':
|
if k == 'developer_comments':
|
||||||
assert six.text_type(
|
assert str(getattr(addon, k)) == str(data[k])
|
||||||
getattr(addon, k)) == six.text_type(data[k])
|
|
||||||
elif k == 'whiteboard-public':
|
elif k == 'whiteboard-public':
|
||||||
assert six.text_type(
|
assert str(addon.whiteboard.public) == str(data[k])
|
||||||
addon.whiteboard.public) == six.text_type(data[k])
|
|
||||||
else:
|
else:
|
||||||
assert getattr(addon, k) == (data[k] == 'on')
|
assert getattr(addon, k) == (data[k] == 'on')
|
||||||
|
|
||||||
|
@ -1594,8 +1590,7 @@ class TestEditTechnical(BaseTestEdit):
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
for k in data:
|
for k in data:
|
||||||
if k == 'developer_comments':
|
if k == 'developer_comments':
|
||||||
assert six.text_type(
|
assert str(getattr(addon, k)) == str(data[k])
|
||||||
getattr(addon, k)) == six.text_type(data[k])
|
|
||||||
else:
|
else:
|
||||||
assert getattr(addon, k) == (data[k] == 'on')
|
assert getattr(addon, k) == (data[k] == 'on')
|
||||||
|
|
||||||
|
@ -1726,7 +1721,7 @@ class TestEditDescribeStaticThemeListed(StaticMixin, BaseTestEditDescribe,
|
||||||
self._feature_addon()
|
self._feature_addon()
|
||||||
data = self.get_dict()
|
data = self.get_dict()
|
||||||
self.client.post(self.describe_edit_url, data)
|
self.client.post(self.describe_edit_url, data)
|
||||||
assert six.text_type(self.get_addon().name) == data['name']
|
assert str(self.get_addon().name) == data['name']
|
||||||
|
|
||||||
def test_theme_preview_shown(self):
|
def test_theme_preview_shown(self):
|
||||||
response = self.client.get(self.url)
|
response = self.client.get(self.url)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
"""Tests related to the ``devhub.addons.owner`` view."""
|
"""Tests related to the ``devhub.addons.owner`` view."""
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
@ -49,7 +47,7 @@ class TestEditPolicy(TestOwnership):
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
addon = self.get_addon()
|
addon = self.get_addon()
|
||||||
assert six.text_type(addon.eula) == 'new eula'
|
assert str(addon.eula) == 'new eula'
|
||||||
assert addon.eula.id == old_eula.id
|
assert addon.eula.id == old_eula.id
|
||||||
|
|
||||||
def test_delete_eula(self):
|
def test_delete_eula(self):
|
||||||
|
@ -128,8 +126,8 @@ class TestEditLicense(TestOwnership):
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
license = self.get_version().license
|
license = self.get_version().license
|
||||||
assert six.text_type(license.text) == 'text'
|
assert str(license.text) == 'text'
|
||||||
assert six.text_type(license.name) == 'name'
|
assert str(license.name) == 'name'
|
||||||
assert license.builtin == License.OTHER
|
assert license.builtin == License.OTHER
|
||||||
|
|
||||||
def test_success_edit_custom(self):
|
def test_success_edit_custom(self):
|
||||||
|
@ -141,8 +139,8 @@ class TestEditLicense(TestOwnership):
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
license_two = self.get_version().license
|
license_two = self.get_version().license
|
||||||
assert six.text_type(license_two.text) == 'woo'
|
assert str(license_two.text) == 'woo'
|
||||||
assert six.text_type(license_two.name) == 'name'
|
assert str(license_two.name) == 'name'
|
||||||
assert license_two.builtin == License.OTHER
|
assert license_two.builtin == License.OTHER
|
||||||
assert license_two.id == license_one.id
|
assert license_two.id == license_one.id
|
||||||
|
|
||||||
|
@ -155,14 +153,14 @@ class TestEditLicense(TestOwnership):
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
license_two = self.get_version().license
|
license_two = self.get_version().license
|
||||||
assert six.text_type(license_two.text) == 'text'
|
assert str(license_two.text) == 'text'
|
||||||
assert six.text_type(license_two.name) == 'name'
|
assert str(license_two.name) == 'name'
|
||||||
assert license_two.builtin == License.OTHER
|
assert license_two.builtin == License.OTHER
|
||||||
assert license_one != license_two
|
assert license_one != license_two
|
||||||
|
|
||||||
# Make sure the old license wasn't edited.
|
# Make sure the old license wasn't edited.
|
||||||
license = License.objects.get(builtin=1)
|
license = License.objects.get(builtin=1)
|
||||||
assert six.text_type(license.name) == 'bsd'
|
assert str(license.name) == 'bsd'
|
||||||
|
|
||||||
data = self.formset(builtin=1)
|
data = self.formset(builtin=1)
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
|
@ -182,8 +180,8 @@ class TestEditLicense(TestOwnership):
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
license = self.get_version().license
|
license = self.get_version().license
|
||||||
assert six.text_type(license.text) == 'text'
|
assert str(license.text) == 'text'
|
||||||
assert six.text_type(license.name) == 'Custom License'
|
assert str(license.name) == 'Custom License'
|
||||||
assert license.builtin == License.OTHER
|
assert license.builtin == License.OTHER
|
||||||
|
|
||||||
def test_no_version(self):
|
def test_no_version(self):
|
||||||
|
@ -196,11 +194,11 @@ class TestEditLicense(TestOwnership):
|
||||||
|
|
||||||
def test_license_details_links(self):
|
def test_license_details_links(self):
|
||||||
# Check that builtin licenses get details links.
|
# Check that builtin licenses get details links.
|
||||||
doc = pq(six.text_type(LicenseForm(version=self.version)))
|
doc = pq(str(LicenseForm(version=self.version)))
|
||||||
for license in License.objects.builtins():
|
for license in License.objects.builtins():
|
||||||
radio = 'input.license[value="%s"]' % license.builtin
|
radio = 'input.license[value="%s"]' % license.builtin
|
||||||
assert doc(radio).parent().text() == (
|
assert doc(radio).parent().text() == (
|
||||||
six.text_type(license.name) + ' Details')
|
str(license.name) + ' Details')
|
||||||
assert doc(radio + '+ a').attr('href') == license.url
|
assert doc(radio + '+ a').attr('href') == license.url
|
||||||
assert doc('input[name=builtin]:last-child').parent().text() == 'Other'
|
assert doc('input[name=builtin]:last-child').parent().text() == 'Other'
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import io
|
||||||
import stat
|
import stat
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files import temp
|
from django.core.files import temp
|
||||||
|
@ -14,11 +16,8 @@ from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import responses
|
import responses
|
||||||
import six
|
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from six import text_type
|
|
||||||
from six.moves.urllib_parse import urlencode
|
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
|
@ -86,7 +85,7 @@ class TestSubmitBase(TestCase):
|
||||||
with tarfile.open(fileobj=source, mode=mode) as tar_file:
|
with tarfile.open(fileobj=source, mode=mode) as tar_file:
|
||||||
tar_info = tarfile.TarInfo('foo')
|
tar_info = tarfile.TarInfo('foo')
|
||||||
tar_info.size = len(data)
|
tar_info.size = len(data)
|
||||||
tar_file.addfile(tar_info, six.BytesIO(data))
|
tar_file.addfile(tar_info, io.BytesIO(data))
|
||||||
|
|
||||||
source.seek(0)
|
source.seek(0)
|
||||||
return source
|
return source
|
||||||
|
@ -1141,7 +1140,7 @@ class DetailsPageMixin(object):
|
||||||
report = AkismetReport.objects.get()
|
report = AkismetReport.objects.get()
|
||||||
assert report.comment_type == 'product-name'
|
assert report.comment_type == 'product-name'
|
||||||
assert report.comment == u'spám'
|
assert report.comment == u'spám'
|
||||||
assert text_type(self.addon.name) != u'spám'
|
assert str(self.addon.name) != u'spám'
|
||||||
|
|
||||||
comment_check_mock.assert_called_once()
|
comment_check_mock.assert_called_once()
|
||||||
|
|
||||||
|
@ -1159,7 +1158,7 @@ class DetailsPageMixin(object):
|
||||||
report = AkismetReport.objects.get()
|
report = AkismetReport.objects.get()
|
||||||
assert report.comment_type == 'product-name'
|
assert report.comment_type == 'product-name'
|
||||||
assert report.comment == u'spám'
|
assert report.comment == u'spám'
|
||||||
assert text_type(self.addon.name) == u'spám'
|
assert str(self.addon.name) == u'spám'
|
||||||
assert b'spam' not in response.content
|
assert b'spam' not in response.content
|
||||||
|
|
||||||
comment_check_mock.assert_called_once()
|
comment_check_mock.assert_called_once()
|
||||||
|
@ -1675,7 +1674,7 @@ class TestAddonSubmitFinish(TestSubmitBase):
|
||||||
self.client.get(self.url)
|
self.client.get(self.url)
|
||||||
context = {
|
context = {
|
||||||
'addon_name': 'Delicious Bookmarks',
|
'addon_name': 'Delicious Bookmarks',
|
||||||
'app': six.text_type(amo.FIREFOX.pretty),
|
'app': str(amo.FIREFOX.pretty),
|
||||||
'detail_url': 'http://b.ro/en-US/firefox/addon/a3615/',
|
'detail_url': 'http://b.ro/en-US/firefox/addon/a3615/',
|
||||||
'version_url': 'http://b.ro/en-US/developers/addon/a3615/versions',
|
'version_url': 'http://b.ro/en-US/developers/addon/a3615/versions',
|
||||||
'edit_url': 'http://b.ro/en-US/developers/addon/a3615/edit',
|
'edit_url': 'http://b.ro/en-US/developers/addon/a3615/edit',
|
||||||
|
@ -1692,7 +1691,7 @@ class TestAddonSubmitFinish(TestSubmitBase):
|
||||||
self.client.get(self.url)
|
self.client.get(self.url)
|
||||||
context = {
|
context = {
|
||||||
'addon_name': 'Delicious Bookmarks',
|
'addon_name': 'Delicious Bookmarks',
|
||||||
'app': six.text_type(amo.FIREFOX.pretty),
|
'app': str(amo.FIREFOX.pretty),
|
||||||
'detail_url': 'http://b.ro/en-US/firefox/addon/a3615/',
|
'detail_url': 'http://b.ro/en-US/firefox/addon/a3615/',
|
||||||
'version_url': 'http://b.ro/en-US/developers/addon/a3615/versions',
|
'version_url': 'http://b.ro/en-US/developers/addon/a3615/versions',
|
||||||
'edit_url': 'http://b.ro/en-US/developers/addon/a3615/edit',
|
'edit_url': 'http://b.ro/en-US/developers/addon/a3615/edit',
|
||||||
|
@ -1712,7 +1711,7 @@ class TestAddonSubmitFinish(TestSubmitBase):
|
||||||
self.client.get(self.url)
|
self.client.get(self.url)
|
||||||
context = {
|
context = {
|
||||||
'addon_name': 'Delicious Bookmarks',
|
'addon_name': 'Delicious Bookmarks',
|
||||||
'app': six.text_type(amo.FIREFOX.pretty),
|
'app': str(amo.FIREFOX.pretty),
|
||||||
'detail_url': 'http://b.ro/en-US/firefox/addon/a3615/',
|
'detail_url': 'http://b.ro/en-US/firefox/addon/a3615/',
|
||||||
'version_url': 'http://b.ro/en-US/developers/addon/a3615/versions',
|
'version_url': 'http://b.ro/en-US/developers/addon/a3615/versions',
|
||||||
'edit_url': 'http://b.ro/en-US/developers/addon/a3615/edit',
|
'edit_url': 'http://b.ro/en-US/developers/addon/a3615/edit',
|
||||||
|
@ -2091,7 +2090,7 @@ class VersionSubmitUploadMixin(object):
|
||||||
assert doc('#theme-wizard').attr('data-version') == '3.0'
|
assert doc('#theme-wizard').attr('data-version') == '3.0'
|
||||||
assert doc('input#theme-name').attr('type') == 'hidden'
|
assert doc('input#theme-name').attr('type') == 'hidden'
|
||||||
assert doc('input#theme-name').attr('value') == (
|
assert doc('input#theme-name').attr('value') == (
|
||||||
six.text_type(self.addon.name))
|
str(self.addon.name))
|
||||||
# Existing colors should be the default values for the fields
|
# Existing colors should be the default values for the fields
|
||||||
assert doc('#frame').attr('value') == '#123456'
|
assert doc('#frame').attr('value') == '#123456'
|
||||||
assert doc('#tab_background_text').attr('value') == 'rgba(1,2,3,0.4)'
|
assert doc('#tab_background_text').attr('value') == 'rgba(1,2,3,0.4)'
|
||||||
|
@ -2152,7 +2151,7 @@ class VersionSubmitUploadMixin(object):
|
||||||
assert doc('#theme-wizard').attr('data-version') == '3.0'
|
assert doc('#theme-wizard').attr('data-version') == '3.0'
|
||||||
assert doc('input#theme-name').attr('type') == 'hidden'
|
assert doc('input#theme-name').attr('type') == 'hidden'
|
||||||
assert doc('input#theme-name').attr('value') == (
|
assert doc('input#theme-name').attr('value') == (
|
||||||
six.text_type(self.addon.name))
|
str(self.addon.name))
|
||||||
# Existing colors should be the default values for the fields
|
# Existing colors should be the default values for the fields
|
||||||
assert doc('#frame').attr('value') == '#123456'
|
assert doc('#frame').attr('value') == '#123456'
|
||||||
assert doc('#tab_background_text').attr('value') == 'rgba(1,2,3,0.4)'
|
assert doc('#tab_background_text').attr('value') == 'rgba(1,2,3,0.4)'
|
||||||
|
@ -2514,9 +2513,9 @@ class TestVersionSubmitDetails(TestSubmitBase):
|
||||||
# metadata is missing, name, slug, summary and category are required to
|
# metadata is missing, name, slug, summary and category are required to
|
||||||
# be present.
|
# be present.
|
||||||
data = {
|
data = {
|
||||||
'name': six.text_type(self.addon.name),
|
'name': str(self.addon.name),
|
||||||
'slug': self.addon.slug,
|
'slug': self.addon.slug,
|
||||||
'summary': six.text_type(self.addon.summary),
|
'summary': str(self.addon.summary),
|
||||||
|
|
||||||
'form-0-categories': [22, 1],
|
'form-0-categories': [22, 1],
|
||||||
'form-0-application': 1,
|
'form-0-application': 1,
|
||||||
|
@ -2581,7 +2580,7 @@ class TestVersionSubmitDetailsFirstListed(TestAddonSubmitDetails):
|
||||||
report = AkismetReport.objects.first()
|
report = AkismetReport.objects.first()
|
||||||
assert report.comment_type == 'product-name'
|
assert report.comment_type == 'product-name'
|
||||||
assert report.comment == u'spám'
|
assert report.comment == u'spám'
|
||||||
assert text_type(self.addon.name) != u'spám'
|
assert str(self.addon.name) != u'spám'
|
||||||
report = AkismetReport.objects.last()
|
report = AkismetReport.objects.last()
|
||||||
assert report.comment_type == 'product-summary'
|
assert report.comment_type == 'product-summary'
|
||||||
assert report.comment == u'Delicious Bookmarks is the official'
|
assert report.comment == u'Delicious Bookmarks is the official'
|
||||||
|
@ -2605,7 +2604,7 @@ class TestVersionSubmitDetailsFirstListed(TestAddonSubmitDetails):
|
||||||
report = AkismetReport.objects.first()
|
report = AkismetReport.objects.first()
|
||||||
assert report.comment_type == 'product-name'
|
assert report.comment_type == 'product-name'
|
||||||
assert report.comment == u'spám'
|
assert report.comment == u'spám'
|
||||||
assert text_type(self.addon.name) == u'spám' # It changed
|
assert str(self.addon.name) == u'spám' # It changed
|
||||||
report = AkismetReport.objects.last()
|
report = AkismetReport.objects.last()
|
||||||
assert report.comment_type == 'product-summary'
|
assert report.comment_type == 'product-summary'
|
||||||
assert report.comment == u'Delicious Bookmarks is the official'
|
assert report.comment == u'Delicious Bookmarks is the official'
|
||||||
|
@ -2629,7 +2628,7 @@ class TestVersionSubmitDetailsFirstListed(TestAddonSubmitDetails):
|
||||||
report = AkismetReport.objects.first()
|
report = AkismetReport.objects.first()
|
||||||
assert report.comment_type == 'product-name'
|
assert report.comment_type == 'product-name'
|
||||||
assert report.comment == u'spám'
|
assert report.comment == u'spám'
|
||||||
assert text_type(self.addon.name) == u'spám' # It changed
|
assert str(self.addon.name) == u'spám' # It changed
|
||||||
report = AkismetReport.objects.last()
|
report = AkismetReport.objects.last()
|
||||||
assert report.comment_type == 'product-summary'
|
assert report.comment_type == 'product-summary'
|
||||||
assert report.comment == u'Delicious Bookmarks is the official'
|
assert report.comment == u'Delicious Bookmarks is the official'
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.core.files import temp
|
||||||
from django.core.files.base import File as DjangoFile
|
from django.core.files.base import File as DjangoFile
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
@ -312,7 +311,7 @@ class TestVersion(TestCase):
|
||||||
entry = ActivityLog.objects.get()
|
entry = ActivityLog.objects.get()
|
||||||
assert entry.action == amo.LOG.USER_DISABLE.id
|
assert entry.action == amo.LOG.USER_DISABLE.id
|
||||||
msg = entry.to_string()
|
msg = entry.to_string()
|
||||||
assert six.text_type(self.addon.name) in msg, ("Unexpected: %r" % msg)
|
assert str(self.addon.name) in msg, ("Unexpected: %r" % msg)
|
||||||
|
|
||||||
@mock.patch('olympia.files.models.File.hide_disabled_file')
|
@mock.patch('olympia.files.models.File.hide_disabled_file')
|
||||||
def test_user_can_disable_addon_pending_version(self, hide_mock):
|
def test_user_can_disable_addon_pending_version(self, hide_mock):
|
||||||
|
@ -339,7 +338,7 @@ class TestVersion(TestCase):
|
||||||
entry = ActivityLog.objects.get()
|
entry = ActivityLog.objects.get()
|
||||||
assert entry.action == amo.LOG.USER_DISABLE.id
|
assert entry.action == amo.LOG.USER_DISABLE.id
|
||||||
msg = entry.to_string()
|
msg = entry.to_string()
|
||||||
assert six.text_type(self.addon.name) in msg, ("Unexpected: %r" % msg)
|
assert str(self.addon.name) in msg, ("Unexpected: %r" % msg)
|
||||||
|
|
||||||
@mock.patch('olympia.files.models.File.hide_disabled_file')
|
@mock.patch('olympia.files.models.File.hide_disabled_file')
|
||||||
def test_disabling_addon_awaiting_review_disables_version(self, hide_mock):
|
def test_disabling_addon_awaiting_review_disables_version(self, hide_mock):
|
||||||
|
@ -372,7 +371,7 @@ class TestVersion(TestCase):
|
||||||
entry = ActivityLog.objects.get()
|
entry = ActivityLog.objects.get()
|
||||||
assert entry.action == amo.LOG.USER_ENABLE.id
|
assert entry.action == amo.LOG.USER_ENABLE.id
|
||||||
msg = entry.to_string()
|
msg = entry.to_string()
|
||||||
assert six.text_type(self.addon.name) in msg, ("Unexpected: %r" % msg)
|
assert str(self.addon.name) in msg, ("Unexpected: %r" % msg)
|
||||||
|
|
||||||
def test_unprivileged_user_cant_disable_addon(self):
|
def test_unprivileged_user_cant_disable_addon(self):
|
||||||
self.addon.update(disabled_by_user=False)
|
self.addon.update(disabled_by_user=False)
|
||||||
|
@ -693,8 +692,8 @@ class TestVersionEditDetails(TestVersionEditBase):
|
||||||
response = self.client.post(self.url, data)
|
response = self.client.post(self.url, data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
version = self.get_version()
|
version = self.get_version()
|
||||||
assert six.text_type(version.release_notes) == 'xx'
|
assert str(version.release_notes) == 'xx'
|
||||||
assert six.text_type(version.approval_notes) == 'yy'
|
assert str(version.approval_notes) == 'yy'
|
||||||
|
|
||||||
def test_version_number_redirect(self):
|
def test_version_number_redirect(self):
|
||||||
url = self.url.replace(str(self.version.id), self.version.version)
|
url = self.url.replace(str(self.version.id), self.version.version)
|
||||||
|
@ -904,8 +903,8 @@ class TestVersionEditSearchEngine(TestVersionEditMixin, TestCase):
|
||||||
response = self.client.post(self.url, dd)
|
response = self.client.post(self.url, dd)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
version = Addon.objects.get(id=4594).current_version
|
version = Addon.objects.get(id=4594).current_version
|
||||||
assert six.text_type(version.release_notes) == 'xx'
|
assert str(version.release_notes) == 'xx'
|
||||||
assert six.text_type(version.approval_notes) == 'yy'
|
assert str(version.approval_notes) == 'yy'
|
||||||
|
|
||||||
def test_no_compat(self):
|
def test_no_compat(self):
|
||||||
response = self.client.get(self.url)
|
response = self.client.get(self.url)
|
||||||
|
|
|
@ -7,7 +7,6 @@ from django.forms import ValidationError
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
import waffle
|
import waffle
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
import olympia.core.logger
|
import olympia.core.logger
|
||||||
|
|
||||||
|
@ -329,7 +328,7 @@ def fetch_existing_translations_from_addon(addon, properties):
|
||||||
translation_ids = [id_ for id_ in translation_ids_gen if id_]
|
translation_ids = [id_ for id_ in translation_ids_gen if id_]
|
||||||
# Just get all the values together to make it simplier
|
# Just get all the values together to make it simplier
|
||||||
return {
|
return {
|
||||||
text_type(value)
|
str(value)
|
||||||
for value in Translation.objects.filter(id__in=translation_ids)}
|
for value in Translation.objects.filter(id__in=translation_ids)}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from django_statsd.clients import statsd
|
from django_statsd.clients import statsd
|
||||||
|
@ -463,19 +462,19 @@ def ownership(request, addon_id, addon):
|
||||||
if action:
|
if action:
|
||||||
ActivityLog.create(
|
ActivityLog.create(
|
||||||
action, author.user,
|
action, author.user,
|
||||||
six.text_type(author.get_role_display()), addon)
|
str(author.get_role_display()), addon)
|
||||||
if (author._original_user_id and
|
if (author._original_user_id and
|
||||||
author.user_id != author._original_user_id):
|
author.user_id != author._original_user_id):
|
||||||
ActivityLog.create(
|
ActivityLog.create(
|
||||||
amo.LOG.REMOVE_USER_WITH_ROLE,
|
amo.LOG.REMOVE_USER_WITH_ROLE,
|
||||||
(UserProfile, author._original_user_id),
|
(UserProfile, author._original_user_id),
|
||||||
six.text_type(author.get_role_display()), addon)
|
str(author.get_role_display()), addon)
|
||||||
|
|
||||||
for author in user_form.deleted_objects:
|
for author in user_form.deleted_objects:
|
||||||
author.delete()
|
author.delete()
|
||||||
ActivityLog.create(
|
ActivityLog.create(
|
||||||
amo.LOG.REMOVE_USER_WITH_ROLE, author.user,
|
amo.LOG.REMOVE_USER_WITH_ROLE, author.user,
|
||||||
six.text_type(author.get_role_display()), addon)
|
str(author.get_role_display()), addon)
|
||||||
authors_emails.add(author.user.email)
|
authors_emails.add(author.user.email)
|
||||||
mail_user_changes(
|
mail_user_changes(
|
||||||
author=author,
|
author=author,
|
||||||
|
@ -1556,8 +1555,8 @@ def _submit_finish(request, addon, version):
|
||||||
# We can use locale-prefixed URLs because the submitter probably
|
# We can use locale-prefixed URLs because the submitter probably
|
||||||
# speaks the same language by the time he/she reads the email.
|
# speaks the same language by the time he/she reads the email.
|
||||||
context = {
|
context = {
|
||||||
'addon_name': six.text_type(addon.name),
|
'addon_name': str(addon.name),
|
||||||
'app': six.text_type(request.APP.pretty),
|
'app': str(request.APP.pretty),
|
||||||
'detail_url': absolutify(addon.get_url_path()),
|
'detail_url': absolutify(addon.get_url_path()),
|
||||||
'version_url': absolutify(addon.get_dev_url('versions')),
|
'version_url': absolutify(addon.get_dev_url('versions')),
|
||||||
'edit_url': absolutify(addon.get_dev_url('edit')),
|
'edit_url': absolutify(addon.get_dev_url('edit')),
|
||||||
|
|
|
@ -5,8 +5,6 @@ from django.utils import translation
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.addons.models import Addon
|
from olympia.addons.models import Addon
|
||||||
from olympia.discovery.models import DiscoveryItem
|
from olympia.discovery.models import DiscoveryItem
|
||||||
|
|
||||||
|
@ -20,8 +18,7 @@ class SlugOrPkChoiceField(forms.ModelChoiceField):
|
||||||
"""A ModelChoiceField that supports entering slugs instead of PKs for
|
"""A ModelChoiceField that supports entering slugs instead of PKs for
|
||||||
convenience."""
|
convenience."""
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
if (value and isinstance(value, six.string_types) and
|
if (value and isinstance(value, str) and not value.isdigit()):
|
||||||
not value.isdigit()):
|
|
||||||
try:
|
try:
|
||||||
value = self.queryset.values_list(
|
value = self.queryset.values_list(
|
||||||
'pk', flat=True).get(slug=value)
|
'pk', flat=True).get(slug=value)
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from django.utils.html import conditional_escape, format_html
|
from django.utils.html import conditional_escape, format_html
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.addons.models import Addon, update_search_index
|
from olympia.addons.models import Addon, update_search_index
|
||||||
from olympia.amo.models import ModelBase, OnChangeMixin
|
from olympia.amo.models import ModelBase, OnChangeMixin
|
||||||
from olympia.amo.templatetags.jinja_helpers import absolutify
|
from olympia.amo.templatetags.jinja_helpers import absolutify
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class DiscoveryItem(OnChangeMixin, ModelBase):
|
class DiscoveryItem(OnChangeMixin, ModelBase):
|
||||||
RECOMMENDED = 'Recommended'
|
RECOMMENDED = 'Recommended'
|
||||||
PENDING_RECOMMENDATION = 'Pending Recommendation'
|
PENDING_RECOMMENDATION = 'Pending Recommendation'
|
||||||
|
@ -63,7 +59,7 @@ class DiscoveryItem(OnChangeMixin, ModelBase):
|
||||||
'new versions will be reviewed for recommended status.')
|
'new versions will be reviewed for recommended status.')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self.addon)
|
return str(self.addon)
|
||||||
|
|
||||||
def build_querystring(self):
|
def build_querystring(self):
|
||||||
qs = QueryDict(mutable=True)
|
qs = QueryDict(mutable=True)
|
||||||
|
@ -76,7 +72,7 @@ class DiscoveryItem(OnChangeMixin, ModelBase):
|
||||||
return qs.urlencode()
|
return qs.urlencode()
|
||||||
|
|
||||||
def _build_heading(self, html=False):
|
def _build_heading(self, html=False):
|
||||||
addon_name = six.text_type(self.custom_addon_name or self.addon.name)
|
addon_name = str(self.custom_addon_name or self.addon.name)
|
||||||
custom_heading = ugettext(
|
custom_heading = ugettext(
|
||||||
self.custom_heading) if self.custom_heading else None
|
self.custom_heading) if self.custom_heading else None
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.amo.tests import TestCase, addon_factory, user_factory
|
from olympia.amo.tests import TestCase, addon_factory, user_factory
|
||||||
from olympia.amo.urlresolvers import django_reverse, reverse
|
from olympia.amo.urlresolvers import django_reverse, reverse
|
||||||
|
@ -111,7 +109,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url, {
|
self.detail_url, {
|
||||||
'addon': six.text_type(addon.pk),
|
'addon': str(addon.pk),
|
||||||
'custom_addon_name': u'Xäxâxàxaxaxa !',
|
'custom_addon_name': u'Xäxâxàxaxaxa !',
|
||||||
'custom_heading': u'This heading is totally custom.',
|
'custom_heading': u'This heading is totally custom.',
|
||||||
'custom_description': u'This description is as well!',
|
'custom_description': u'This description is as well!',
|
||||||
|
@ -144,7 +142,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
# Change add-on using the slug.
|
# Change add-on using the slug.
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url,
|
self.detail_url,
|
||||||
{'addon': six.text_type(addon2.slug)}, follow=True)
|
{'addon': str(addon2.slug)}, follow=True)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
item.reload()
|
item.reload()
|
||||||
assert DiscoveryItem.objects.count() == 1
|
assert DiscoveryItem.objects.count() == 1
|
||||||
|
@ -152,7 +150,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
|
|
||||||
# Change add-on using the id.
|
# Change add-on using the id.
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url, {'addon': six.text_type(addon.pk)}, follow=True)
|
self.detail_url, {'addon': str(addon.pk)}, follow=True)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
item.reload()
|
item.reload()
|
||||||
assert DiscoveryItem.objects.count() == 1
|
assert DiscoveryItem.objects.count() == 1
|
||||||
|
@ -182,7 +180,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
# Try changing using an unknown id.
|
# Try changing using an unknown id.
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url,
|
self.detail_url,
|
||||||
{'addon': six.text_type(addon2.pk + 666)}, follow=True)
|
{'addon': str(addon2.pk + 666)}, follow=True)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert not response.context_data['adminform'].form.is_valid()
|
assert not response.context_data['adminform'].form.is_valid()
|
||||||
assert 'addon' in response.context_data['adminform'].form.errors
|
assert 'addon' in response.context_data['adminform'].form.errors
|
||||||
|
@ -192,7 +190,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
# Try changing using a non-public add-on id.
|
# Try changing using a non-public add-on id.
|
||||||
addon3 = addon_factory(status=amo.STATUS_DISABLED)
|
addon3 = addon_factory(status=amo.STATUS_DISABLED)
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url, {'addon': six.text_type(addon3.pk)}, follow=True)
|
self.detail_url, {'addon': str(addon3.pk)}, follow=True)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert not response.context_data['adminform'].form.is_valid()
|
assert not response.context_data['adminform'].form.is_valid()
|
||||||
assert 'addon' in response.context_data['adminform'].form.errors
|
assert 'addon' in response.context_data['adminform'].form.errors
|
||||||
|
@ -202,7 +200,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
# Try changing to an add-on that is already used by another item.
|
# Try changing to an add-on that is already used by another item.
|
||||||
item2 = DiscoveryItem.objects.create(addon=addon2)
|
item2 = DiscoveryItem.objects.create(addon=addon2)
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url, {'addon': six.text_type(addon2.pk)}, follow=True)
|
self.detail_url, {'addon': str(addon2.pk)}, follow=True)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert not response.context_data['adminform'].form.is_valid()
|
assert not response.context_data['adminform'].form.is_valid()
|
||||||
assert 'addon' in response.context_data['adminform'].form.errors
|
assert 'addon' in response.context_data['adminform'].form.errors
|
||||||
|
@ -243,7 +241,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
assert DiscoveryItem.objects.count() == 0
|
assert DiscoveryItem.objects.count() == 0
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.add_url, {
|
self.add_url, {
|
||||||
'addon': six.text_type(addon.pk),
|
'addon': str(addon.pk),
|
||||||
'custom_addon_name': u'Xäxâxàxaxaxa !',
|
'custom_addon_name': u'Xäxâxàxaxaxa !',
|
||||||
'custom_heading': u'This heading is totally custom.',
|
'custom_heading': u'This heading is totally custom.',
|
||||||
'custom_description': u'This description is as well!',
|
'custom_description': u'This description is as well!',
|
||||||
|
@ -265,9 +263,9 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
response = self.client.get(self.add_url, follow=True)
|
response = self.client.get(self.add_url, follow=True)
|
||||||
assert response.status_code == 403
|
assert response.status_code == 403
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.add_url, {
|
self.add_url,
|
||||||
'addon': six.text_type(addon.pk),
|
{'addon': str(addon.pk)},
|
||||||
}, follow=True)
|
follow=True)
|
||||||
assert response.status_code == 403
|
assert response.status_code == 403
|
||||||
assert DiscoveryItem.objects.count() == 0
|
assert DiscoveryItem.objects.count() == 0
|
||||||
|
|
||||||
|
@ -285,7 +283,7 @@ class TestDiscoveryAdmin(TestCase):
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.detail_url, {
|
self.detail_url, {
|
||||||
'addon': six.text_type(addon.pk),
|
'addon': str(addon.pk),
|
||||||
'custom_addon_name': u'Noooooô !',
|
'custom_addon_name': u'Noooooô !',
|
||||||
'custom_heading': u'I should not be able to do this.',
|
'custom_heading': u'I should not be able to do this.',
|
||||||
'custom_description': u'This is wrong.',
|
'custom_description': u'This is wrong.',
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from waffle import switch_is_active
|
from waffle import switch_is_active
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
@ -49,10 +48,9 @@ class DiscoveryTestMixin(object):
|
||||||
addon = item.addon
|
addon = item.addon
|
||||||
assert result['addon']['id'] == item.addon_id == addon.pk
|
assert result['addon']['id'] == item.addon_id == addon.pk
|
||||||
if flat_name:
|
if flat_name:
|
||||||
assert result['addon']['name'] == six.text_type(addon.name)
|
assert result['addon']['name'] == str(addon.name)
|
||||||
else:
|
else:
|
||||||
assert result['addon']['name'] == {
|
assert result['addon']['name'] == {'en-US': str(addon.name)}
|
||||||
'en-US': six.text_type(addon.name)}
|
|
||||||
assert result['addon']['slug'] == addon.slug
|
assert result['addon']['slug'] == addon.slug
|
||||||
assert result['addon']['icon_url'] == absolutify(
|
assert result['addon']['icon_url'] == absolutify(
|
||||||
addon.get_icon_url(64))
|
addon.get_icon_url(64))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from six.moves.urllib_parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
|
|
|
@ -12,12 +12,9 @@ from django.core.files.storage import default_storage as storage
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.utils.encoding import (
|
from django.utils.encoding import force_bytes, force_text
|
||||||
force_bytes, force_text, python_2_unicode_compatible)
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from django_extensions.db.fields.json import JSONField
|
from django_extensions.db.fields.json import JSONField
|
||||||
from django_statsd.clients import statsd
|
from django_statsd.clients import statsd
|
||||||
|
|
||||||
|
@ -39,7 +36,6 @@ from olympia.lib.cache import memoize
|
||||||
log = olympia.core.logger.getLogger('z.files')
|
log = olympia.core.logger.getLogger('z.files')
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class File(OnChangeMixin, ModelBase):
|
class File(OnChangeMixin, ModelBase):
|
||||||
id = PositiveAutoField(primary_key=True)
|
id = PositiveAutoField(primary_key=True)
|
||||||
STATUS_CHOICES = amo.STATUS_CHOICES_FILE
|
STATUS_CHOICES = amo.STATUS_CHOICES_FILE
|
||||||
|
@ -92,7 +88,7 @@ class File(OnChangeMixin, ModelBase):
|
||||||
db_table = 'files'
|
db_table = 'files'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self.id)
|
return str(self.id)
|
||||||
|
|
||||||
def get_platform_display(self):
|
def get_platform_display(self):
|
||||||
return force_text(amo.PLATFORMS[self.platform].name)
|
return force_text(amo.PLATFORMS[self.platform].name)
|
||||||
|
@ -372,7 +368,7 @@ class File(OnChangeMixin, ModelBase):
|
||||||
# Remove any duplicate permissions.
|
# Remove any duplicate permissions.
|
||||||
permissions = set()
|
permissions = set()
|
||||||
permissions = [p for p in self._webext_permissions.permissions
|
permissions = [p for p in self._webext_permissions.permissions
|
||||||
if isinstance(p, six.string_types) and not
|
if isinstance(p, str) and not
|
||||||
(p in permissions or permissions.add(p))]
|
(p in permissions or permissions.add(p))]
|
||||||
return permissions
|
return permissions
|
||||||
|
|
||||||
|
@ -490,7 +486,6 @@ def track_file_status_change(file_):
|
||||||
statsd.incr('file_status_change.all.status_{}'.format(file_.status))
|
statsd.incr('file_status_change.all.status_{}'.format(file_.status))
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class FileUpload(ModelBase):
|
class FileUpload(ModelBase):
|
||||||
"""Created when a file is uploaded for validation/submission."""
|
"""Created when a file is uploaded for validation/submission."""
|
||||||
uuid = models.UUIDField(default=uuid.uuid4, editable=False)
|
uuid = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
|
@ -520,7 +515,7 @@ class FileUpload(ModelBase):
|
||||||
db_table = 'file_uploads'
|
db_table = 'file_uploads'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self.uuid.hex)
|
return str(self.uuid.hex)
|
||||||
|
|
||||||
def save(self, *args, **kw):
|
def save(self, *args, **kw):
|
||||||
if self.validation:
|
if self.validation:
|
||||||
|
@ -638,7 +633,7 @@ class FileValidation(ModelBase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, file, validation):
|
def from_json(cls, file, validation):
|
||||||
if isinstance(validation, six.string_types):
|
if isinstance(validation, str):
|
||||||
validation = json.loads(validation)
|
validation = json.loads(validation)
|
||||||
|
|
||||||
if 'metadata' in validation:
|
if 'metadata' in validation:
|
||||||
|
@ -686,6 +681,6 @@ class WebextPermission(ModelBase):
|
||||||
|
|
||||||
def nfd_str(u):
|
def nfd_str(u):
|
||||||
"""Uses NFD to normalize unicode strings."""
|
"""Uses NFD to normalize unicode strings."""
|
||||||
if isinstance(u, six.text_type):
|
if isinstance(u, str):
|
||||||
return unicodedata.normalize('NFD', u).encode('utf-8')
|
return unicodedata.normalize('NFD', u).encode('utf-8')
|
||||||
return u
|
return u
|
||||||
|
|
|
@ -11,7 +11,6 @@ from django.core.files.storage import default_storage as storage
|
||||||
|
|
||||||
import flufl.lock
|
import flufl.lock
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
@ -486,17 +485,6 @@ class TestSafeZipFile(TestCase, amo.tests.AMOPaths):
|
||||||
assert zip_file.is_valid
|
assert zip_file.is_valid
|
||||||
assert b'locale browser de' in zip_file.read('chrome.manifest')
|
assert b'locale browser de' in zip_file.read('chrome.manifest')
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
six.PY3,
|
|
||||||
reason='Python 3 seems to handle filenames in that zip just fine.')
|
|
||||||
def test_invalid_zip_encoding(self):
|
|
||||||
with pytest.raises(forms.ValidationError) as exc:
|
|
||||||
SafeZip(self.xpi_path('invalid-cp437-encoding.xpi'))
|
|
||||||
|
|
||||||
assert isinstance(exc.value, forms.ValidationError)
|
|
||||||
assert exc.value.message.endswith(
|
|
||||||
'Please make sure all filenames are utf-8 or latin1 encoded.')
|
|
||||||
|
|
||||||
def test_not_secure(self):
|
def test_not_secure(self):
|
||||||
zip_file = SafeZip(self.xpi_path('extension'))
|
zip_file = SafeZip(self.xpi_path('extension'))
|
||||||
assert not zip_file.is_signed()
|
assert not zip_file.is_signed()
|
||||||
|
|
|
@ -7,6 +7,7 @@ import time
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -14,9 +15,7 @@ from django.forms import ValidationError
|
||||||
|
|
||||||
import flufl.lock
|
import flufl.lock
|
||||||
import lxml
|
import lxml
|
||||||
from unittest import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
from defusedxml.common import EntitiesForbidden, NotSupportedError
|
from defusedxml.common import EntitiesForbidden, NotSupportedError
|
||||||
from waffle.testutils import override_switch
|
from waffle.testutils import override_switch
|
||||||
|
@ -989,7 +988,7 @@ def test_parse_search_empty_shortname():
|
||||||
utils.parse_search(fname)
|
utils.parse_search(fname)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
six.text_type(excinfo.value.message) ==
|
str(excinfo.value.message) ==
|
||||||
'Could not parse uploaded file, missing or empty <ShortName> element')
|
'Could not parse uploaded file, missing or empty <ShortName> element')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,16 @@ import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.http import http_date, quote_etag
|
from django.utils.http import http_date, quote_etag
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
from six.moves.urllib_parse import urlparse
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.addons.models import Addon
|
from olympia.addons.models import Addon
|
||||||
|
@ -459,7 +458,7 @@ class TestFileViewer(FilesBase, TestCase):
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
|
|
||||||
def test_unicode_unicode_tmp_path(self):
|
def test_unicode_unicode_tmp_path(self):
|
||||||
with override_settings(TMP_PATH=six.text_type(settings.TMP_PATH)):
|
with override_settings(TMP_PATH=str(settings.TMP_PATH)):
|
||||||
self.test_unicode()
|
self.test_unicode()
|
||||||
|
|
||||||
def test_serve_no_token(self):
|
def test_serve_no_token(self):
|
||||||
|
|
|
@ -14,7 +14,6 @@ import tempfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -27,7 +26,6 @@ from django.utils.translation import ugettext
|
||||||
|
|
||||||
import flufl.lock
|
import flufl.lock
|
||||||
import rdflib
|
import rdflib
|
||||||
import six
|
|
||||||
|
|
||||||
from xml.parsers.expat import ExpatError
|
from xml.parsers.expat import ExpatError
|
||||||
|
|
||||||
|
@ -86,7 +84,7 @@ def get_filepath(fileorpath):
|
||||||
This supports various input formats, a path, a django `File` object,
|
This supports various input formats, a path, a django `File` object,
|
||||||
`olympia.files.File`, a `FileUpload` or just a regular file-like object.
|
`olympia.files.File`, a `FileUpload` or just a regular file-like object.
|
||||||
"""
|
"""
|
||||||
if isinstance(fileorpath, six.string_types):
|
if isinstance(fileorpath, str):
|
||||||
return fileorpath
|
return fileorpath
|
||||||
elif isinstance(fileorpath, DjangoFile):
|
elif isinstance(fileorpath, DjangoFile):
|
||||||
return fileorpath
|
return fileorpath
|
||||||
|
@ -106,7 +104,7 @@ def id_to_path(pk):
|
||||||
12 => 2/12/12
|
12 => 2/12/12
|
||||||
123456 => 6/56/123456
|
123456 => 6/56/123456
|
||||||
"""
|
"""
|
||||||
pk = six.text_type(pk)
|
pk = str(pk)
|
||||||
path = [pk[-1]]
|
path = [pk[-1]]
|
||||||
if len(pk) >= 2:
|
if len(pk) >= 2:
|
||||||
path.append(pk[-2:])
|
path.append(pk[-2:])
|
||||||
|
@ -126,7 +124,7 @@ def get_file(fileorpath):
|
||||||
|
|
||||||
|
|
||||||
def make_xpi(files):
|
def make_xpi(files):
|
||||||
file_obj = six.BytesIO()
|
file_obj = io.BytesIO()
|
||||||
zip_file = zipfile.ZipFile(file_obj, 'w')
|
zip_file = zipfile.ZipFile(file_obj, 'w')
|
||||||
for path, data in files.items():
|
for path, data in files.items():
|
||||||
zip_file.writestr(path, data)
|
zip_file.writestr(path, data)
|
||||||
|
@ -326,7 +324,7 @@ class RDFExtractor(object):
|
||||||
match = list(self.rdf.objects(ctx, predicate=self.uri(name)))
|
match = list(self.rdf.objects(ctx, predicate=self.uri(name)))
|
||||||
# These come back as rdflib.Literal, which subclasses unicode.
|
# These come back as rdflib.Literal, which subclasses unicode.
|
||||||
if match:
|
if match:
|
||||||
return six.text_type(match[0])
|
return str(match[0])
|
||||||
|
|
||||||
def apps(self):
|
def apps(self):
|
||||||
rv = []
|
rv = []
|
||||||
|
@ -802,7 +800,7 @@ class SafeZip(object):
|
||||||
if type == 'jar':
|
if type == 'jar':
|
||||||
parts = path.split('!')
|
parts = path.split('!')
|
||||||
for part in parts[:-1]:
|
for part in parts[:-1]:
|
||||||
jar = self.__class__(six.BytesIO(jar.zip_file.read(part)))
|
jar = self.__class__(io.BytesIO(jar.zip_file.read(part)))
|
||||||
path = parts[-1]
|
path = parts[-1]
|
||||||
return jar.read(path[1:] if path.startswith('/') else path)
|
return jar.read(path[1:] if path.startswith('/') else path)
|
||||||
|
|
||||||
|
@ -1269,7 +1267,7 @@ def resolve_i18n_message(message, messages, locale, default_locale=None):
|
||||||
:param messages: A dictionary of messages, e.g the return value
|
:param messages: A dictionary of messages, e.g the return value
|
||||||
of `extract_translations`.
|
of `extract_translations`.
|
||||||
"""
|
"""
|
||||||
if not message or not isinstance(message, six.string_types):
|
if not message or not isinstance(message, str):
|
||||||
# Don't even attempt to extract invalid data.
|
# Don't even attempt to extract invalid data.
|
||||||
# See https://github.com/mozilla/addons-server/issues/3067
|
# See https://github.com/mozilla/addons-server/issues/3067
|
||||||
# for more details
|
# for more details
|
||||||
|
@ -1326,7 +1324,7 @@ def get_background_images(file_obj, theme_data, header_only=False):
|
||||||
try:
|
try:
|
||||||
with zipfile.ZipFile(xpi, 'r') as source:
|
with zipfile.ZipFile(xpi, 'r') as source:
|
||||||
for url in image_urls:
|
for url in image_urls:
|
||||||
_, file_ext = os.path.splitext(text_type(url).lower())
|
_, file_ext = os.path.splitext(str(url).lower())
|
||||||
if file_ext not in amo.THEME_BACKGROUND_EXTS:
|
if file_ext not in amo.THEME_BACKGROUND_EXTS:
|
||||||
# Just extract image files.
|
# Just extract image files.
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import requests
|
import requests
|
||||||
import six
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -35,7 +34,7 @@ class Command(BaseCommand):
|
||||||
help='only consider this specific add-on type'
|
help='only consider this specific add-on type'
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--query', metavar='type', type=six.text_type,
|
'--query', metavar='type', type=str,
|
||||||
help='only consider add-ons matching this query'
|
help='only consider add-ons matching this query'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.addons.models import Category
|
from olympia.addons.models import Category
|
||||||
from olympia.amo.tests import TestCase
|
from olympia.amo.tests import TestCase
|
||||||
from olympia.constants.applications import APPS
|
from olympia.constants.applications import APPS
|
||||||
|
@ -23,7 +21,7 @@ class CategoriesTests(TestCase):
|
||||||
|
|
||||||
category = Category.objects.get(
|
category = Category.objects.get(
|
||||||
id=CATEGORIES[APPS['android'].id][ADDON_EXTENSION]['shopping'].id)
|
id=CATEGORIES[APPS['android'].id][ADDON_EXTENSION]['shopping'].id)
|
||||||
assert six.text_type(category.name) == u'Shopping'
|
assert str(category.name) == u'Shopping'
|
||||||
|
|
||||||
# Re-generating should not create any more.
|
# Re-generating should not create any more.
|
||||||
data = generate_categories(APPS['android'], ADDON_EXTENSION)
|
data = generate_categories(APPS['android'], ADDON_EXTENSION)
|
||||||
|
@ -33,4 +31,4 @@ class CategoriesTests(TestCase):
|
||||||
# Name should still be the same.
|
# Name should still be the same.
|
||||||
category = Category.objects.get(
|
category = Category.objects.get(
|
||||||
id=CATEGORIES[APPS['android'].id][ADDON_EXTENSION]['shopping'].id)
|
id=CATEGORIES[APPS['android'].id][ADDON_EXTENSION]['shopping'].id)
|
||||||
assert six.text_type(category.name) == u'Shopping'
|
assert str(category.name) == u'Shopping'
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.addons.models import Addon
|
from olympia.addons.models import Addon
|
||||||
from olympia.amo.tests import TestCase
|
from olympia.amo.tests import TestCase
|
||||||
|
@ -25,7 +23,7 @@ class CollectionsTests(TestCase):
|
||||||
def test_collections_themes_translations(self):
|
def test_collections_themes_translations(self):
|
||||||
generate_collection(self.addon)
|
generate_collection(self.addon)
|
||||||
with self.activate(locale='es'):
|
with self.activate(locale='es'):
|
||||||
collection_name = six.text_type(Collection.objects.last().name)
|
collection_name = str(Collection.objects.last().name)
|
||||||
assert collection_name.startswith(u'(español) ')
|
assert collection_name.startswith(u'(español) ')
|
||||||
|
|
||||||
def test_collections_addons_generation(self):
|
def test_collections_addons_generation(self):
|
||||||
|
@ -38,5 +36,5 @@ class CollectionsTests(TestCase):
|
||||||
def test_collections_addons_translations(self):
|
def test_collections_addons_translations(self):
|
||||||
generate_collection(self.addon, APPS['android'])
|
generate_collection(self.addon, APPS['android'])
|
||||||
with self.activate(locale='es'):
|
with self.activate(locale='es'):
|
||||||
collection_name = six.text_type(Collection.objects.last().name)
|
collection_name = str(Collection.objects.last().name)
|
||||||
assert collection_name.startswith(u'(español) ')
|
assert collection_name.startswith(u'(español) ')
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.addons.models import Addon
|
from olympia.addons.models import Addon
|
||||||
from olympia.amo.tests import TestCase
|
from olympia.amo.tests import TestCase
|
||||||
|
@ -21,5 +19,5 @@ class RatingsTests(TestCase):
|
||||||
assert UserProfile.objects.count() == 3
|
assert UserProfile.objects.count() == 3
|
||||||
for n, review in enumerate(Rating.objects.all().order_by('pk')):
|
for n, review in enumerate(Rating.objects.all().order_by('pk')):
|
||||||
assert review.addon == self.addon
|
assert review.addon == self.addon
|
||||||
assert six.text_type(review.body) == u'Test Review %d' % (n + 1)
|
assert str(review.body) == u'Test Review %d' % (n + 1)
|
||||||
assert review.user.email.endswith('@example.com')
|
assert review.user.email.endswith('@example.com')
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
def generate_translations(item):
|
def generate_translations(item):
|
||||||
"""Generate French and Spanish translations for the given `item`."""
|
"""Generate French and Spanish translations for the given `item`."""
|
||||||
fr_prefix = u'(français) '
|
fr_prefix = u'(français) '
|
||||||
es_prefix = u'(español) '
|
es_prefix = u'(español) '
|
||||||
oldname = six.text_type(item.name)
|
oldname = str(item.name)
|
||||||
item.name = {'en': oldname,
|
item.name = {'en': oldname,
|
||||||
'fr': fr_prefix + oldname,
|
'fr': fr_prefix + oldname,
|
||||||
'es': es_prefix + oldname}
|
'es': es_prefix + oldname}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import django.contrib.messages as django_messages
|
import django.contrib.messages as django_messages
|
||||||
|
|
||||||
|
@ -8,10 +9,8 @@ from django.contrib import admin
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
import responses
|
import responses
|
||||||
import six
|
|
||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from pyquery import PyQuery as pq
|
from pyquery import PyQuery as pq
|
||||||
|
@ -225,7 +224,7 @@ class TestAkismetReportsAddon(BaseAkismetReportsModelTest, TestCase):
|
||||||
'comment_author': user.name,
|
'comment_author': user.name,
|
||||||
'comment_author_email': user.email,
|
'comment_author_email': user.email,
|
||||||
'comment_author_url': user.homepage,
|
'comment_author_url': user.homepage,
|
||||||
'comment_content': six.text_type(addon.name),
|
'comment_content': str(addon.name),
|
||||||
'comment_date_gmt': time_now,
|
'comment_date_gmt': time_now,
|
||||||
'blog_charset': 'utf-8',
|
'blog_charset': 'utf-8',
|
||||||
'is_test': not settings.AKISMET_REAL_SUBMIT,
|
'is_test': not settings.AKISMET_REAL_SUBMIT,
|
||||||
|
@ -331,7 +330,7 @@ class TestAkismetAdmin(TestCase):
|
||||||
[ham_report_not_already_submitted.pk], True)
|
[ham_report_not_already_submitted.pk], True)
|
||||||
assert len(django_messages.get_messages(request)) == 1
|
assert len(django_messages.get_messages(request)) == 1
|
||||||
for message in django_messages.get_messages(request):
|
for message in django_messages.get_messages(request):
|
||||||
assert six.text_type(message) == (
|
assert str(message) == (
|
||||||
'1 Ham reports submitted as Spam; 5 reports ignored')
|
'1 Ham reports submitted as Spam; 5 reports ignored')
|
||||||
|
|
||||||
@mock.patch('olympia.lib.akismet.admin.submit_to_akismet.delay')
|
@mock.patch('olympia.lib.akismet.admin.submit_to_akismet.delay')
|
||||||
|
@ -351,7 +350,7 @@ class TestAkismetAdmin(TestCase):
|
||||||
[r.id for r in spam_reports_not_already_submitted], False)
|
[r.id for r in spam_reports_not_already_submitted], False)
|
||||||
assert len(django_messages.get_messages(request)) == 1
|
assert len(django_messages.get_messages(request)) == 1
|
||||||
for message in django_messages.get_messages(request):
|
for message in django_messages.get_messages(request):
|
||||||
assert six.text_type(message) == (
|
assert str(message) == (
|
||||||
'2 Spam reports submitted as Ham; 4 reports ignored')
|
'2 Spam reports submitted as Ham; 4 reports ignored')
|
||||||
|
|
||||||
def test_submit_spam_button_on_ham_page(self):
|
def test_submit_spam_button_on_ham_page(self):
|
||||||
|
|
|
@ -11,7 +11,6 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.utils.encoding import force_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import six
|
|
||||||
import waffle
|
import waffle
|
||||||
|
|
||||||
from django_statsd.clients import statsd
|
from django_statsd.clients import statsd
|
||||||
|
@ -175,7 +174,7 @@ def sign_file(file_obj):
|
||||||
.format(file_obj.version.pk))
|
.format(file_obj.version.pk))
|
||||||
|
|
||||||
# Sign the file. If there's any exception, we skip the rest.
|
# Sign the file. If there's any exception, we skip the rest.
|
||||||
cert_serial_num = six.text_type(call_signing(file_obj))
|
cert_serial_num = str(call_signing(file_obj))
|
||||||
|
|
||||||
size = storage.size(file_obj.current_file_path)
|
size = storage.size(file_obj.current_file_path)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import io
|
||||||
|
|
||||||
from django.core import management
|
from django.core import management
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.test.testcases import TransactionTestCase
|
from django.test.testcases import TransactionTestCase
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.amo.tests import (
|
from olympia.amo.tests import (
|
||||||
addon_factory, create_switch, ESTestCase, reverse_ns)
|
addon_factory, create_switch, ESTestCase, reverse_ns)
|
||||||
from olympia.amo.utils import urlparams
|
from olympia.amo.utils import urlparams
|
||||||
|
@ -86,7 +85,7 @@ class TestIndexCommand(ESTestCase):
|
||||||
# This is to start a reindexation in the background.
|
# This is to start a reindexation in the background.
|
||||||
class ReindexThread(threading.Thread):
|
class ReindexThread(threading.Thread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.stdout = six.StringIO()
|
self.stdout = io.StringIO()
|
||||||
super(ReindexThread, self).__init__()
|
super(ReindexThread, self).__init__()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from collections import namedtuple
|
|
||||||
import uuid
|
import uuid
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
|
@ -8,7 +7,8 @@ import tempfile
|
||||||
import sys
|
import sys
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
|
||||||
import six
|
from collections import namedtuple
|
||||||
|
|
||||||
import pygit2
|
import pygit2
|
||||||
import magic
|
import magic
|
||||||
|
|
||||||
|
@ -466,7 +466,7 @@ class AddonGitRepository(object):
|
||||||
"""
|
"""
|
||||||
# When `commit` is a commit hash, e.g passed to us through the API
|
# When `commit` is a commit hash, e.g passed to us through the API
|
||||||
# serializers we have to fetch the actual commit object to proceed.
|
# serializers we have to fetch the actual commit object to proceed.
|
||||||
if isinstance(commit, six.string_types):
|
if isinstance(commit, str):
|
||||||
commit = self.git_repository.revparse_single(commit)
|
commit = self.git_repository.revparse_single(commit)
|
||||||
|
|
||||||
return self.git_repository[commit.tree[EXTRACTED_PREFIX].oid]
|
return self.git_repository[commit.tree[EXTRACTED_PREFIX].oid]
|
||||||
|
|
|
@ -4,7 +4,6 @@ from django.conf import settings
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
from olympia.amo.utils import from_string
|
from olympia.amo.utils import from_string
|
||||||
|
|
||||||
|
@ -227,7 +226,7 @@ def test_css(getmtime, time):
|
||||||
'css': {'compiled': ['css/impala/buttons.less']}})
|
'css': {'compiled': ['css/impala/buttons.less']}})
|
||||||
@mock.patch('olympia.lib.jingo_minify_helpers.os.path.getmtime')
|
@mock.patch('olympia.lib.jingo_minify_helpers.os.path.getmtime')
|
||||||
@mock.patch('olympia.lib.jingo_minify_helpers.subprocess')
|
@mock.patch('olympia.lib.jingo_minify_helpers.subprocess')
|
||||||
@mock.patch('%s.open' % ('__builtin__' if six.PY2 else 'builtins'), spec=True)
|
@mock.patch('builtins.open', spec=True)
|
||||||
def test_compiled_css(open_mock, subprocess_mock, getmtime_mock):
|
def test_compiled_css(open_mock, subprocess_mock, getmtime_mock):
|
||||||
getmtime_mock.side_effect = [
|
getmtime_mock.side_effect = [
|
||||||
# The first call is for the source
|
# The first call is for the source
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче