fix: avoid mutables as defaults. Compute date default arguments at runtime rather than loadtime. (#4144)

This commit is contained in:
Robert Sparks 2022-07-06 14:39:36 -05:00 committed by GitHub
parent 75bb797d9e
commit b988850985
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 83 additions and 21 deletions

View file

@ -226,7 +226,11 @@ class JsonExportMixin(object):
# content_type = 'application/json'
# return HttpResponse(serialize([ obj ], sort_keys=True, indent=3)[2:-2], content_type=content_type)
def json_view(self, request, filter={}, expand=[]):
def json_view(self, request, filter=None, expand=None):
if expand is None:
expand = []
if filter is None:
filter = {}
qfilter, exclude = filter_from_queryargs(request)
for k in list(qfilter.keys()):
if k.startswith("_"):

View file

@ -650,10 +650,12 @@ def nice_consensus(consensus):
}
return mapping[consensus]
def has_same_ballot(doc, date1, date2=datetime.date.today()):
def has_same_ballot(doc, date1, date2=None):
""" Test if the most recent ballot created before the end of date1
is the same as the most recent ballot created before the
end of date 2. """
if date2 is None:
date2 = datetime.date.today()
ballot1 = doc.latest_event(BallotDocEvent,type='created_ballot',time__lt=date1+datetime.timedelta(days=1))
ballot2 = doc.latest_event(BallotDocEvent,type='created_ballot',time__lt=date2+datetime.timedelta(days=1))
return ballot1==ballot2
@ -926,7 +928,9 @@ def extract_complete_replaces_ancestor_mapping_for_docs(names):
def make_rev_history(doc):
# return document history data for inclusion in doc.json (used by timeline)
def get_predecessors(doc, predecessors=[]):
def get_predecessors(doc, predecessors=None):
if predecessors is None:
predecessors = []
if hasattr(doc, 'relateddocument_set'):
for alias in doc.related_that_doc('replaces'):
for document in alias.docs.all():
@ -935,7 +939,9 @@ def make_rev_history(doc):
predecessors.extend(get_predecessors(document, predecessors))
return predecessors
def get_ancestors(doc, ancestors = []):
def get_ancestors(doc, ancestors = None):
if ancestors is None:
ancestors = []
if hasattr(doc, 'relateddocument_set'):
for alias in doc.related_that('replaces'):
for document in alias.docs.all():
@ -1328,4 +1334,4 @@ def fuzzy_find_documents(name, rev=None):
rev = None # found a doc by name with rev = None, so update that
FoundDocuments = namedtuple('FoundDocuments', 'documents matched_name matched_rev')
return FoundDocuments(docs, name, rev)
return FoundDocuments(docs, name, rev)

View file

@ -600,7 +600,9 @@ def get_eligibility_date(nomcom=None, date=None):
else:
return datetime.date(datetime.date.today().year,5,1)
def previous_five_meetings(date = datetime.date.today()):
def previous_five_meetings(date = None):
if date is None:
date = datetime.date.today()
return Meeting.objects.filter(type='ietf',date__lte=date).order_by('-date')[:5]
def three_of_five_eligible(previous_five, queryset=None):

View file

@ -13,7 +13,9 @@ register = template.Library()
@register.filter
def is_nomcom_eligible(person, date=datetime.date.today()):
def is_nomcom_eligible(person, date=None):
if date is None:
date = datetime.date.today()
return is_eligible(person=person, date=date)
@ -88,4 +90,4 @@ def email_person_link(email, **kwargs):
"title": title,
"class": cls,
"with_email": with_email,
}
}

View file

@ -140,10 +140,13 @@ ReviewAssignmentData = namedtuple("ReviewAssignmentData", [
"request_to_assignment_days", "assignment_to_closure_days", "request_to_closure_days"])
def extract_review_assignment_data(teams=None, reviewers=None, time_from=None, time_to=None, ordering=[]):
def extract_review_assignment_data(teams=None, reviewers=None, time_from=None, time_to=None, ordering=None):
"""Yield data on each review assignment, sorted by (*ordering, assigned_on)
for easy use with itertools.groupby. Valid entries in *ordering are "team" and "reviewer"."""
if ordering is None:
ordering = []
filters = Q()
if teams:

View file

@ -133,7 +133,9 @@ def add_labeled_top_series_from_bins(chart_data, bins, limit):
})
def document_stats(request, stats_type=None):
def build_document_stats_url(stats_type_override=Ellipsis, get_overrides={}):
def build_document_stats_url(stats_type_override=Ellipsis, get_overrides=None):
if get_overrides is None:
get_overrides={}
kwargs = {
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
}
@ -762,7 +764,9 @@ def meeting_stats(request, num=None, stats_type=None):
if num is not None:
meeting = get_object_or_404(Meeting, number=num, type="ietf")
def build_meeting_stats_url(number=None, stats_type_override=Ellipsis, get_overrides={}):
def build_meeting_stats_url(number=None, stats_type_override=Ellipsis, get_overrides=None):
if get_overrides is None:
get_overrides = {}
kwargs = {
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
}
@ -1009,7 +1013,9 @@ def review_stats(request, stats_type=None, acronym=None):
# and statistics type) are incorporated directly into the URL to
# be a bit nicer.
def build_review_stats_url(stats_type_override=Ellipsis, acronym_override=Ellipsis, get_overrides={}):
def build_review_stats_url(stats_type_override=Ellipsis, acronym_override=Ellipsis, get_overrides=None):
if get_overrides is None:
get_overrides = {}
kwargs = {
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
}

View file

@ -405,8 +405,12 @@ def send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=F
return msg
def parse_preformatted(preformatted, extra={}, override={}):
def parse_preformatted(preformatted, extra=None, override=None):
"""Parse preformatted string containing mail with From:, To:, ...,"""
if extra is None:
extra = {}
if override is None:
override = {}
assert isinstance(preformatted, str)
msg = message_from_bytes(preformatted.encode('utf-8'))
msg.set_charset('UTF-8')
@ -458,19 +462,26 @@ def parse_preformatted(preformatted, extra={}, override={}):
assertion('len(list(set(v))) == len(v)')
return (msg, extra, bcc)
def send_mail_preformatted(request, preformatted, extra={}, override={}):
def send_mail_preformatted(request, preformatted, extra=None, override=None):
"""Parse preformatted string containing mail with From:, To:, ...,
and send it through the standard IETF mail interface (inserting
extra headers as needed)."""
if extra is None:
extra = {}
if override is None:
override = {}
(msg, extra, bcc) = parse_preformatted(preformatted, extra, override)
txt = msg.get_payload()
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], txt, extra=extra, bcc=bcc)
return msg
def send_mail_message(request, message, extra={}):
def send_mail_message(request, message, extra=None):
"""Send a Message object."""
# note that this doesn't handle MIME messages at the moment
if extra is None:
extra = {}
assertion('isinstance(message.to, str) and isinstance(message.cc, str) and isinstance(message.bcc, str)')
e = extra.copy()

View file

@ -157,7 +157,9 @@ class Command(DumpdataCommand):
yield obj
def handle(self, filenames=[], **options):
def handle(self, filenames=None, **options):
if filenames is None:
filenames = []
self.verbosity = int(options.get('verbosity'))
format = options['format']
indent = options['indent']

View file

@ -1036,11 +1036,14 @@ class IetfTestRunner(DiscoverRunner):
test_paths = [ os.path.join(*app.split('.')) for app in test_apps ]
return test_apps, test_paths
def run_tests(self, test_labels, extra_tests=[], **kwargs):
def run_tests(self, test_labels, extra_tests=None, **kwargs):
global old_destroy, old_create, test_database_name, template_coverage_collection, code_coverage_collection, url_coverage_collection
from django.db import connection
from ietf.doc.tests import TemplateTagTest
if extra_tests is None:
extra_tests=[]
# Tests that involve switching back and forth between the real
# database and the test database are way too dangerous to run
# against the production database

View file

@ -67,7 +67,7 @@ class SMTPTestServer(smtpd.SMTPServer):
#channel = SMTPTestChannel(self, conn, addr)
SMTPTestChannel(self, conn, addr)
def process_message(self, peer, mailfrom, rcpttos, data, mail_options=[], rcpt_options=[]):
def process_message(self, peer, mailfrom, rcpttos, data, mail_options=None, rcpt_options=None):
self.inbox.append(data)

View file

@ -110,7 +110,7 @@ def format_addresses(addresses, header_name=None, charset=None):
return header
def build_mail(text, html=None, attachments=[], embeddeds=[]):
def build_mail(text, html=None, attachments=None, embeddeds=None):
"""
Generate the core of the email message regarding the parameters.
The structure of the MIME email may vary, but the general one is as follow::
@ -184,6 +184,11 @@ def build_mail(text, html=None, attachments=[], embeddeds=[]):
--===limit1==--
"""
if attachments is None:
attachments = []
if embeddeds is None:
embeddeds = []
main=text_part=html_part=None
if text:
content, charset=text
@ -234,7 +239,7 @@ def build_mail(text, html=None, attachments=[], embeddeds=[]):
return main
def complete_mail(message, sender, recipients, subject, default_charset, cc=[], bcc=[], message_id_string=None, date=None, headers=[]):
def complete_mail(message, sender, recipients, subject, default_charset, cc=None, bcc=None, message_id_string=None, date=None, headers=None):
"""
Fill in the From, To, Cc, Subject, Date and Message-Id I{headers} of
one existing message regarding the parameters.
@ -312,6 +317,13 @@ def complete_mail(message, sender, recipients, subject, default_charset, cc=[],
else:
return address
if cc is None:
cc=[]
if bcc is None:
bcc=[]
if headers is None:
headers=[]
mail_from=getaddr(sender[1])
rcpt_to=list(map(getaddr, recipients))
rcpt_to.extend(list(map(getaddr, cc)))
@ -341,7 +353,7 @@ def complete_mail(message, sender, recipients, subject, default_charset, cc=[],
return payload, mail_from, rcpt_to, msg_id
def compose_mail(sender, recipients, subject, default_charset, text, html=None, attachments=[], embeddeds=[], cc=[], bcc=[], message_id_string=None, date=None, headers=[]):
def compose_mail(sender, recipients, subject, default_charset, text, html=None, attachments=None, embeddeds=None, cc=None, bcc=None, message_id_string=None, date=None, headers=None):
"""
Compose an email regarding the arguments. Call L{build_mail()} and
L{complete_mail()} at once.
@ -356,6 +368,17 @@ def compose_mail(sender, recipients, subject, default_charset, text, html=None,
>>> payload, mail_from, rcpt_to, msg_id=compose_mail((u'Me', 'me@foo.com'), [(u'Him', 'him@bar.com')], u'the subject', 'iso-8859-1', ('Hello world', 'us-ascii'), attachments=[('attached', 'text', 'plain', 'text.txt', 'us-ascii')])
"""
if attachments is None:
attachments=[]
if embeddeds is None:
embeddeds=[]
if cc is None:
cc=[]
if bcc is None:
bcc = []
if headers is None:
headers=[]
message=build_mail(text, html, attachments, embeddeds)
return complete_mail(message, sender, recipients, subject, default_charset, cc, bcc, message_id_string, date, headers)