Fix function declarations with mutable default arguments

This commit is contained in:
Mathieu Pillard 2016-09-19 19:49:42 +02:00
Родитель 893f890296
Коммит 8ddc1c4449
29 изменённых файлов: 178 добавлений и 60 удалений

Просмотреть файл

@ -13,7 +13,11 @@ def setup(app):
app.add_role('src', src_role)
def src_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
def src_role(name, rawtext, text, lineno, inliner, options=None, content=None):
if options is None:
options = {}
if content is None:
content = []
base_url = inliner.document.settings.env.config.src_base_url
if base_url is None:
msg = inliner.reporter.error('src_base_url is not set', line=lineno)

Просмотреть файл

@ -27,7 +27,9 @@ class TestReviewNotesSerializerOutput(TestCase, LogMixin):
self.now = self.days_ago(0)
self.entry = self.log(u'Oh nôes!', amo.LOG.REJECT_VERSION, self.now)
def serialize(self, context={}):
def serialize(self, context=None):
if context is None:
context = {}
context['request'] = self.request
serializer = ActivityLogSerializer(context=context)
return serializer.to_representation(self.entry)

Просмотреть файл

@ -141,14 +141,18 @@ def tags_box(context, addon, tags=None):
@register.inclusion_tag('addons/listing/items.html')
@jinja2.contextfunction
def addon_listing_items(context, addons, show_date=False,
show_downloads=False, src=None, notes={}):
show_downloads=False, src=None, notes=None):
if notes is None:
notes = {}
return new_context(**locals())
@register.inclusion_tag('addons/impala/listing/items.html')
@jinja2.contextfunction
def impala_addon_listing_items(context, addons, field=None, src=None,
dl_src=None, notes={}):
dl_src=None, notes=None):
if notes is None:
notes = {}
if not src:
src = context.get('src')
if not dl_src:
@ -176,8 +180,13 @@ def addon_listing_header(context, url_base, sort_opts, selected):
@register.inclusion_tag('addons/impala/listing/sorter.html')
@jinja2.contextfunction
def impala_addon_listing_header(context, url_base, sort_opts={}, selected=None,
extra_sort_opts={}, search_filter=None):
def impala_addon_listing_header(context, url_base, sort_opts=None,
selected=None, extra_sort_opts=None,
search_filter=None):
if sort_opts is None:
sort_opts = {}
if extra_sort_opts is None:
extra_sort_opts = {}
if search_filter:
selected = search_filter.field
sort_opts = search_filter.opts

Просмотреть файл

@ -198,7 +198,7 @@ class AddonManager(ManagerBase):
status = [amo.STATUS_PUBLIC]
return self.filter(self.valid_q(status), appsupport__app=app.id)
def valid_q(self, status=[], prefix=''):
def valid_q(self, status=None, prefix=''):
"""
Return a Q object that selects a valid Addon with the given statuses.
@ -593,7 +593,9 @@ class Addon(OnChangeMixin, ModelBase):
action=action)
return reverse(view_name, args=[self.slug] + args)
def get_detail_url(self, action='detail', args=[]):
def get_detail_url(self, action='detail', args=None):
if args is None:
args = []
return reverse('addons.%s' % action, args=[self.slug] + args)
def meet_the_dev_url(self):
@ -1509,8 +1511,8 @@ def update_search_index(sender, instance, **kw):
@Addon.on_change
def watch_status(old_attr={}, new_attr={}, instance=None,
sender=None, **kw):
def watch_status(old_attr=None, new_attr=None, instance=None,
sender=None, **kwargs):
"""
Set nomination date if the addon is new in queue or updating.
@ -1521,6 +1523,10 @@ def watch_status(old_attr={}, new_attr={}, instance=None,
to upload a new version.
"""
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
new_status = new_attr.get('status')
old_status = old_attr.get('status')
if (new_status not in amo.UNDER_REVIEW_STATUSES + amo.REVIEWED_STATUSES or
@ -1538,7 +1544,12 @@ def watch_status(old_attr={}, new_attr={}, instance=None,
@Addon.on_change
def watch_disabled(old_attr={}, new_attr={}, instance=None, sender=None, **kw):
def watch_disabled(old_attr=None, new_attr=None, instance=None, sender=None,
**kwargs):
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
attrs = dict((k, v) for k, v in old_attr.items()
if k in ('disabled_by_user', 'status'))
if Addon(**attrs).is_disabled and not instance.is_disabled:
@ -1550,8 +1561,12 @@ def watch_disabled(old_attr={}, new_attr={}, instance=None, sender=None, **kw):
@Addon.on_change
def watch_developer_notes(old_attr={}, new_attr={}, instance=None, sender=None,
**kw):
def watch_developer_notes(old_attr=None, new_attr=None, instance=None,
sender=None, **kwargs):
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
whiteboard_changed = (
new_attr.get('whiteboard') and
old_attr.get('whiteboard') != new_attr.get('whiteboard'))
@ -2217,7 +2232,11 @@ models.signals.post_save.connect(track_new_status,
@Addon.on_change
def track_status_change(old_attr={}, new_attr={}, **kw):
def track_status_change(old_attr=None, new_attr=None, **kw):
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
new_status = new_attr.get('status')
old_status = old_attr.get('status')
if new_status != old_status:

Просмотреть файл

@ -1292,7 +1292,9 @@ class TestAddonModels(TestCase):
assert addon.can_request_review() == ()
def check(self, status, expected, disallow_preliminary=False,
extra_update_kw={}):
extra_update_kw=None):
if extra_update_kw is None:
extra_update_kw = {}
addon = Addon.objects.get(pk=3615)
changes = {'status': status, 'disabled_by_user': False}
changes.update(**extra_update_kw)

Просмотреть файл

@ -1266,7 +1266,9 @@ class TestEula(TestCase):
self.addon = Addon.objects.get(id=11730)
self.url = self.get_url()
def get_url(self, args=[]):
def get_url(self, args=None):
if args is None:
args = []
return reverse('addons.eula', args=[self.addon.slug] + args)
def test_current_version(self):

Просмотреть файл

@ -219,8 +219,12 @@ class OnChangeMixin(object):
For example::
def watch_status(old_attr={}, new_attr={},
instance=None, sender=None, **kw):
def watch_status(old_attr=None, new_attr=None,
instance=None, sender=None, **kwargs):
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
if old_attr.get('status') != new_attr.get('status'):
# ...
new_instance.save(_signal=False)

Просмотреть файл

@ -31,7 +31,9 @@ ADDONS_TEST_FILES = os.path.join(
pytestmark = pytest.mark.django_db
def render(s, context={}):
def render(s, context=None):
if context is None:
context = {}
t = jingo.get_env().from_string(s)
return t.render(context)

Просмотреть файл

@ -27,8 +27,10 @@ def impala_collection_listing_items(context, collections, field=None):
@register.function
def user_collection_list(collections=[], heading='', id='', link=None):
def user_collection_list(collections=None, heading='', id='', link=None):
"""list of collections, as used on the user profile page"""
if collections is None:
collections = []
c = {'collections': collections, 'heading': heading, 'link': link,
'id': id}
template = get_env().get_template('bandwagon/users/collection_list.html')

Просмотреть файл

@ -263,9 +263,11 @@ class Collection(ModelBase):
else:
return settings.STATIC_URL + 'img/icons/collection.png'
def set_addons(self, addon_ids, comments={}):
def set_addons(self, addon_ids, comments=None):
"""Replace the current add-ons with a new list of add-on ids."""
order = dict((a, idx) for idx, a in enumerate(addon_ids))
if comments is None:
comments = {}
order = {a: idx for idx, a in enumerate(addon_ids)}
# Partition addon_ids into add/update/remove buckets.
existing = set(self.addons.using('default')

Просмотреть файл

@ -127,7 +127,11 @@ def get_filter(request, base=None):
@non_atomic_requests
def render_cat(request, template, data={}, extra={}):
def render_cat(request, template, data=None, extra=None):
if extra is None:
extra = {}
if data is None:
data = {}
data.update(dict(search_cat='collections'))
return render(request, template, data, **extra)

Просмотреть файл

@ -207,7 +207,12 @@ class TestReporterDetail(TestCase):
app_multiprocess_enabled=app_multiprocess_enabled)
self.reports.append(report.pk)
def check_table(self, data={}, good=0, bad=0, appver=None, report_pks=[]):
def check_table(
self, data=None, good=0, bad=0, appver=None, report_pks=None):
if data is None:
data = {}
if report_pks is None:
report_pks = []
r = self.client.get(self.url, data)
assert r.status_code == 200

Просмотреть файл

@ -22,7 +22,9 @@ register.function(acl.check_addon_ownership)
@register.inclusion_tag('devhub/addons/listing/items.html')
@jinja2.contextfunction
def dev_addon_listing_items(context, addons, src=None, notes={}):
def dev_addon_listing_items(context, addons, src=None, notes=None):
if notes is None:
notes = {}
return new_context(**locals())

Просмотреть файл

@ -268,7 +268,7 @@ class ActivityLog(ModelBase):
return objs
@arguments.setter
def arguments(self, args=[]):
def arguments(self, args=None):
"""
Takes an object or a tuple of objects and serializes them and stores it
in the db as a json string.

Просмотреть файл

@ -2806,9 +2806,11 @@ class TestUploadErrors(UploadTest):
class AddVersionTest(UploadTest):
def post(self, supported_platforms=[amo.PLATFORM_MAC],
def post(self, supported_platforms=None,
override_validation=False, expected_status=200, source=None,
beta=False, nomination_type=None):
if supported_platforms is None:
supported_platforms = [amo.PLATFORM_MAC]
d = dict(upload=self.upload.uuid.hex, source=source,
supported_platforms=[p.id for p in supported_platforms],
admin_override_validation=override_validation, beta=beta)
@ -3151,6 +3153,8 @@ class UploadAddon(object):
def post(self, supported_platforms=[amo.PLATFORM_ALL], expect_errors=False,
source=None, is_listed=True, status_code=200):
if supported_platforms is None:
supported_platforms = [amo.PLATFORM_ALL]
d = dict(upload=self.upload.uuid.hex, source=source,
supported_platforms=[p.id for p in supported_platforms],
is_unlisted=not is_listed)

Просмотреть файл

@ -1178,7 +1178,9 @@ class TestEditTechnical(TestEdit):
assert not any(r.context['dependency_form'].errors)
self.check_dep_ids(deps.values_list('id', flat=True))
def check_dep_ids(self, expected=[]):
def check_dep_ids(self, expected=None):
if expected is None:
expected = []
a = AddonDependency.objects.values_list('dependent_addon__id',
flat=True)
assert sorted(list(a)) == sorted(expected)

Просмотреть файл

@ -533,7 +533,9 @@ class TestReviewHelper(TestCase):
assert context_key in context_data
assert context_data.get(context_key) in mail.outbox[0].body
def setup_data(self, status, delete=[], is_listed=True):
def setup_data(self, status, delete=None, is_listed=True):
if delete is None:
delete = []
mail.outbox = []
ActivityLog.objects.for_addons(self.helper.addon).delete()
self.addon.update(status=status, is_listed=is_listed)

Просмотреть файл

@ -56,7 +56,9 @@ class EditorTest(TestCase):
a = Addon.objects.create(name='yermom', type=amo.ADDON_EXTENSION)
return Review.objects.create(user=u, addon=a)
def _test_breadcrumbs(self, expected=[]):
def _test_breadcrumbs(self, expected=None):
if expected is None:
expected = []
r = self.client.get(self.url)
expected.insert(0, ('Editor Tools', reverse('editors.home')))
check_links(expected, pq(r.content)('#breadcrumbs li'), verify=False)
@ -612,7 +614,9 @@ class QueueTest(EditorTest):
self.addons = SortedDict()
self.expected_addons = []
def generate_files(self, subset=[]):
def generate_files(self, subset=None):
if subset is None:
subset = []
files = SortedDict([
('Pending One', {
'version_str': '0.1',
@ -1383,7 +1387,9 @@ class TestPerformance(QueueTest):
amo.set_user(UserProfile.objects.get(username='admin'))
self.create_logs()
def get_url(self, args=[]):
def get_url(self, args=None):
if args is None:
args = []
return reverse('editors.performance', args=args)
def create_logs(self):
@ -1488,7 +1494,9 @@ class BaseTestQueueSearch(SearchTest):
fixtures = ['base/users', 'base/appversion']
__test__ = False # this is an abstract test case
def generate_files(self, subset=[]):
def generate_files(self, subset=None):
if subset is None:
subset = []
files = SortedDict([
('Not Admin Reviewed', {
'version_str': '0.1',
@ -3142,7 +3150,9 @@ class TestLimitedReviewerQueue(QueueTest, LimitedReviewerBase):
self.create_limited_user()
self.login_as_limited_reviewer()
def generate_files(self, subset=[]):
def generate_files(self, subset=None):
if subset is None:
subset = []
files = SortedDict([
('Nominated new', {
'version_str': '0.1',

Просмотреть файл

@ -151,7 +151,9 @@ class File(OnChangeMixin, ModelBase):
@classmethod
def from_upload(cls, upload, version, platform, is_beta=False,
parse_data={}):
parse_data=None):
if parse_data is None:
parse_data = {}
addon = version.addon
file_ = cls(version=version, platform=platform)
@ -537,11 +539,15 @@ models.signals.post_save.connect(track_new_status,
@File.on_change
def track_status_change(old_attr={}, new_attr={}, **kw):
def track_status_change(old_attr=None, new_attr=None, **kwargs):
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
new_status = new_attr.get('status')
old_status = old_attr.get('status')
if new_status != old_status:
track_file_status_change(kw['instance'])
track_file_status_change(kwargs['instance'])
def track_file_status_change(file_):

Просмотреть файл

@ -61,7 +61,9 @@ def partition(seq, key):
return ((k, list(v)) for k, v in groups)
def render_xml_to_string(request, template, context={}):
def render_xml_to_string(request, template, context=None):
if context is None:
context = {}
if not jingo._helpers_loaded:
jingo.load_helpers()
@ -73,8 +75,10 @@ def render_xml_to_string(request, template, context={}):
@non_atomic_requests
def render_xml(request, template, context={}, **kwargs):
def render_xml(request, template, context=None, **kwargs):
"""Safely renders xml, stripping out nasty control characters."""
if context is None:
context = {}
rendered = render_xml_to_string(request, template, context)
if 'content_type' not in kwargs:

Просмотреть файл

@ -20,7 +20,9 @@ URL_ENCODED = 'application/x-www-form-urlencoded'
class Client(test.Client):
"""Test client that uses form-urlencoded (like browsers)."""
def post(self, url, data={}, **kw):
def post(self, url, data=None, **kw):
if data is None:
data = {}
if hasattr(data, 'items'):
data = urllib.urlencode(data)
kw['content_type'] = URL_ENCODED

Просмотреть файл

@ -10,7 +10,9 @@ from olympia.reviews.forms import ReviewForm
class HelpersTest(TestCase):
def render(self, s, context={}):
def render(self, s, context=None):
if context is None:
context = {}
t = jingo.get_env().from_string(s)
return t.render(context)

Просмотреть файл

@ -76,10 +76,12 @@ class SearchBase(ESTestCaseWithAddons):
return results
def check_sort_links(self, key, title=None, sort_by=None, reverse=True,
params={}):
r = self.client.get(urlparams(self.url, sort=key, **params))
assert r.status_code == 200
doc = pq(r.content)
params=None):
if params is None:
params = {}
response = self.client.get(urlparams(self.url, sort=key, **params))
assert response.status_code == 200
doc = pq(response.content)
if title:
if hasattr(self, 'MOBILE'):
menu = doc('#sort-menu')
@ -88,7 +90,7 @@ class SearchBase(ESTestCaseWithAddons):
else:
assert doc('#sorter .selected').text() == title
if sort_by:
results = r.context['pager'].object_list
results = response.context['pager'].object_list
if sort_by == 'name':
expected = sorted(results, key=lambda x: unicode(x.name))
else:
@ -1087,8 +1089,10 @@ def test_search_redirects2(test_input):
class TestAjaxSearch(ESTestCaseWithAddons):
def search_addons(self, url, params, addons=[], types=amo.ADDON_TYPES,
def search_addons(self, url, params, addons=None, types=amo.ADDON_TYPES,
src=None):
if addons is None:
addons = []
r = self.client.get(url + '?' + params)
assert r.status_code == 200
data = json.loads(r.content)
@ -1117,7 +1121,9 @@ class TestAjaxSearch(ESTestCaseWithAddons):
class TestGenericAjaxSearch(TestAjaxSearch):
def search_addons(self, params, addons=[]):
def search_addons(self, params, addons=None):
if addons is None:
addons = []
[a.save() for a in Addon.objects.all()]
self.refresh(timesleep=1)
super(TestGenericAjaxSearch, self).search_addons(
@ -1194,15 +1200,17 @@ class TestSearchSuggestions(TestAjaxSearch):
]
self.refresh(timesleep=1)
def search_addons(self, params, addons=[],
def search_addons(self, params, addons=None,
types=views.AddonSuggestionsAjax.types):
super(TestSearchSuggestions, self).search_addons(
self.url, params, addons, types, src='ss')
def search_applications(self, params, apps=[]):
r = self.client.get(self.url + '?' + params)
assert r.status_code == 200
data = json.loads(r.content)
def search_applications(self, params, apps=None):
if apps is None:
apps = []
response = self.client.get(self.url + '?' + params)
assert response.status_code == 200
data = json.loads(response.content)
data = sorted(data, key=lambda x: x['id'])
apps = sorted(apps, key=lambda x: x.id)

Просмотреть файл

@ -341,8 +341,10 @@ def name_query(q):
def _filter_search(request, qs, query, filters, sorting,
sorting_default='-weekly_downloads', types=[]):
sorting_default='-weekly_downloads', types=None):
"""Filter an ES queryset based on a list of filters."""
if types is None:
types = []
APP = request.APP
# Intersection of the form fields present and the filters we want to apply.
show = [f for f in filters if query.get(f)]

Просмотреть файл

@ -4,8 +4,10 @@ import jinja2
@register.inclusion_tag('tags/tag_list.html')
@jinja2.contextfunction
def tag_list(context, addon, tags=[]):
def tag_list(context, addon, tags=None):
"""Display list of tags, with delete buttons."""
if tags is None:
tags = []
c = dict(context.items())
c.update({'addon': addon,

Просмотреть файл

@ -6,8 +6,10 @@ from olympia import amo
from olympia.addons.models import Addon
def render(s, context={}):
def render(s, context=None):
"""Taken from jingo.tests.utils, previously jingo.tests.test_helpers."""
if context is None:
context = {}
t = get_env().from_string(s)
return t.render(context)

Просмотреть файл

@ -277,8 +277,10 @@ class TransField(_TransField, forms.CharField):
"""
@staticmethod
def adapt(cls, opts={}):
def adapt(cls, opts=None):
"""Get a new TransField that subclasses cls instead of CharField."""
if opts is None:
opts = {}
return type('Trans%s' % cls.__name__, (_TransField, cls), opts)

Просмотреть файл

@ -603,7 +603,9 @@ class UserNotification(ModelBase):
db_table = 'users_notifications'
@staticmethod
def update_or_create(update={}, **kwargs):
def update_or_create(update=None, **kwargs):
if update is None:
update = {}
rows = UserNotification.objects.filter(**kwargs).update(**update)
if not rows:
update.update(dict(**kwargs))
@ -685,8 +687,12 @@ class UserHistory(ModelBase):
@UserProfile.on_change
def watch_email(old_attr={}, new_attr={}, instance=None,
def watch_email(old_attr=None, new_attr=None, instance=None,
sender=None, **kw):
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
new_email, old_email = new_attr.get('email'), old_attr.get('email')
if old_email and new_email != old_email:
log.debug('Creating user history for user: %s' % instance.pk)

Просмотреть файл

@ -554,12 +554,17 @@ class Version(OnChangeMixin, ModelBase):
@Version.on_change
def watch_source(old_attr={}, new_attr={}, instance=None, sender=None, **kw):
def watch_source(old_attr=None, new_attr=None, instance=None, sender=None,
**kwargs):
"""Set the "admin_review" flag on the addon if a source file was added.
Source files can be added to any upload, but it only makes sense to admin
flag the addon if it's an extension, not a search tool, dictionary...
"""
if old_attr is None:
old_attr = {}
if new_attr is None:
new_attr = {}
# Only flag extensions (bug 1200621).
if instance.addon.type != amo.ADDON_EXTENSION:
return