fix: avoid mutables as defaults. Compute date default arguments at runtime rather than loadtime. (#4144)
This commit is contained in:
parent
75bb797d9e
commit
b988850985
|
@ -226,7 +226,11 @@ class JsonExportMixin(object):
|
||||||
# content_type = 'application/json'
|
# content_type = 'application/json'
|
||||||
# return HttpResponse(serialize([ obj ], sort_keys=True, indent=3)[2:-2], content_type=content_type)
|
# 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)
|
qfilter, exclude = filter_from_queryargs(request)
|
||||||
for k in list(qfilter.keys()):
|
for k in list(qfilter.keys()):
|
||||||
if k.startswith("_"):
|
if k.startswith("_"):
|
||||||
|
|
|
@ -650,10 +650,12 @@ def nice_consensus(consensus):
|
||||||
}
|
}
|
||||||
return mapping[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
|
""" Test if the most recent ballot created before the end of date1
|
||||||
is the same as the most recent ballot created before the
|
is the same as the most recent ballot created before the
|
||||||
end of date 2. """
|
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))
|
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))
|
ballot2 = doc.latest_event(BallotDocEvent,type='created_ballot',time__lt=date2+datetime.timedelta(days=1))
|
||||||
return ballot1==ballot2
|
return ballot1==ballot2
|
||||||
|
@ -926,7 +928,9 @@ def extract_complete_replaces_ancestor_mapping_for_docs(names):
|
||||||
def make_rev_history(doc):
|
def make_rev_history(doc):
|
||||||
# return document history data for inclusion in doc.json (used by timeline)
|
# 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'):
|
if hasattr(doc, 'relateddocument_set'):
|
||||||
for alias in doc.related_that_doc('replaces'):
|
for alias in doc.related_that_doc('replaces'):
|
||||||
for document in alias.docs.all():
|
for document in alias.docs.all():
|
||||||
|
@ -935,7 +939,9 @@ def make_rev_history(doc):
|
||||||
predecessors.extend(get_predecessors(document, predecessors))
|
predecessors.extend(get_predecessors(document, predecessors))
|
||||||
return predecessors
|
return predecessors
|
||||||
|
|
||||||
def get_ancestors(doc, ancestors = []):
|
def get_ancestors(doc, ancestors = None):
|
||||||
|
if ancestors is None:
|
||||||
|
ancestors = []
|
||||||
if hasattr(doc, 'relateddocument_set'):
|
if hasattr(doc, 'relateddocument_set'):
|
||||||
for alias in doc.related_that('replaces'):
|
for alias in doc.related_that('replaces'):
|
||||||
for document in alias.docs.all():
|
for document in alias.docs.all():
|
||||||
|
|
|
@ -600,7 +600,9 @@ def get_eligibility_date(nomcom=None, date=None):
|
||||||
else:
|
else:
|
||||||
return datetime.date(datetime.date.today().year,5,1)
|
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]
|
return Meeting.objects.filter(type='ietf',date__lte=date).order_by('-date')[:5]
|
||||||
|
|
||||||
def three_of_five_eligible(previous_five, queryset=None):
|
def three_of_five_eligible(previous_five, queryset=None):
|
||||||
|
|
|
@ -13,7 +13,9 @@ register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@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)
|
return is_eligible(person=person, date=date)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -140,10 +140,13 @@ ReviewAssignmentData = namedtuple("ReviewAssignmentData", [
|
||||||
"request_to_assignment_days", "assignment_to_closure_days", "request_to_closure_days"])
|
"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)
|
"""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"."""
|
for easy use with itertools.groupby. Valid entries in *ordering are "team" and "reviewer"."""
|
||||||
|
|
||||||
|
if ordering is None:
|
||||||
|
ordering = []
|
||||||
|
|
||||||
filters = Q()
|
filters = Q()
|
||||||
|
|
||||||
if teams:
|
if teams:
|
||||||
|
|
|
@ -133,7 +133,9 @@ def add_labeled_top_series_from_bins(chart_data, bins, limit):
|
||||||
})
|
})
|
||||||
|
|
||||||
def document_stats(request, stats_type=None):
|
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 = {
|
kwargs = {
|
||||||
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
|
"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:
|
if num is not None:
|
||||||
meeting = get_object_or_404(Meeting, number=num, type="ietf")
|
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 = {
|
kwargs = {
|
||||||
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
|
"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
|
# and statistics type) are incorporated directly into the URL to
|
||||||
# be a bit nicer.
|
# 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 = {
|
kwargs = {
|
||||||
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
|
"stats_type": stats_type if stats_type_override is Ellipsis else stats_type_override,
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,8 +405,12 @@ def send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=F
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def parse_preformatted(preformatted, extra={}, override={}):
|
def parse_preformatted(preformatted, extra=None, override=None):
|
||||||
"""Parse preformatted string containing mail with From:, To:, ...,"""
|
"""Parse preformatted string containing mail with From:, To:, ...,"""
|
||||||
|
if extra is None:
|
||||||
|
extra = {}
|
||||||
|
if override is None:
|
||||||
|
override = {}
|
||||||
assert isinstance(preformatted, str)
|
assert isinstance(preformatted, str)
|
||||||
msg = message_from_bytes(preformatted.encode('utf-8'))
|
msg = message_from_bytes(preformatted.encode('utf-8'))
|
||||||
msg.set_charset('UTF-8')
|
msg.set_charset('UTF-8')
|
||||||
|
@ -458,19 +462,26 @@ def parse_preformatted(preformatted, extra={}, override={}):
|
||||||
assertion('len(list(set(v))) == len(v)')
|
assertion('len(list(set(v))) == len(v)')
|
||||||
return (msg, extra, bcc)
|
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:, ...,
|
"""Parse preformatted string containing mail with From:, To:, ...,
|
||||||
and send it through the standard IETF mail interface (inserting
|
and send it through the standard IETF mail interface (inserting
|
||||||
extra headers as needed)."""
|
extra headers as needed)."""
|
||||||
|
|
||||||
|
if extra is None:
|
||||||
|
extra = {}
|
||||||
|
if override is None:
|
||||||
|
override = {}
|
||||||
|
|
||||||
(msg, extra, bcc) = parse_preformatted(preformatted, extra, override)
|
(msg, extra, bcc) = parse_preformatted(preformatted, extra, override)
|
||||||
txt = msg.get_payload()
|
txt = msg.get_payload()
|
||||||
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], txt, extra=extra, bcc=bcc)
|
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], txt, extra=extra, bcc=bcc)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def send_mail_message(request, message, extra={}):
|
def send_mail_message(request, message, extra=None):
|
||||||
"""Send a Message object."""
|
"""Send a Message object."""
|
||||||
# note that this doesn't handle MIME messages at the moment
|
# 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)')
|
assertion('isinstance(message.to, str) and isinstance(message.cc, str) and isinstance(message.bcc, str)')
|
||||||
|
|
||||||
e = extra.copy()
|
e = extra.copy()
|
||||||
|
|
|
@ -157,7 +157,9 @@ class Command(DumpdataCommand):
|
||||||
yield obj
|
yield obj
|
||||||
|
|
||||||
|
|
||||||
def handle(self, filenames=[], **options):
|
def handle(self, filenames=None, **options):
|
||||||
|
if filenames is None:
|
||||||
|
filenames = []
|
||||||
self.verbosity = int(options.get('verbosity'))
|
self.verbosity = int(options.get('verbosity'))
|
||||||
format = options['format']
|
format = options['format']
|
||||||
indent = options['indent']
|
indent = options['indent']
|
||||||
|
|
|
@ -1036,11 +1036,14 @@ class IetfTestRunner(DiscoverRunner):
|
||||||
test_paths = [ os.path.join(*app.split('.')) for app in test_apps ]
|
test_paths = [ os.path.join(*app.split('.')) for app in test_apps ]
|
||||||
return test_apps, test_paths
|
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
|
global old_destroy, old_create, test_database_name, template_coverage_collection, code_coverage_collection, url_coverage_collection
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from ietf.doc.tests import TemplateTagTest
|
from ietf.doc.tests import TemplateTagTest
|
||||||
|
|
||||||
|
if extra_tests is None:
|
||||||
|
extra_tests=[]
|
||||||
|
|
||||||
# Tests that involve switching back and forth between the real
|
# Tests that involve switching back and forth between the real
|
||||||
# database and the test database are way too dangerous to run
|
# database and the test database are way too dangerous to run
|
||||||
# against the production database
|
# against the production database
|
||||||
|
|
|
@ -67,7 +67,7 @@ class SMTPTestServer(smtpd.SMTPServer):
|
||||||
#channel = SMTPTestChannel(self, conn, addr)
|
#channel = SMTPTestChannel(self, conn, addr)
|
||||||
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)
|
self.inbox.append(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ def format_addresses(addresses, header_name=None, charset=None):
|
||||||
return header
|
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.
|
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::
|
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==--
|
--===limit1==--
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if attachments is None:
|
||||||
|
attachments = []
|
||||||
|
if embeddeds is None:
|
||||||
|
embeddeds = []
|
||||||
|
|
||||||
main=text_part=html_part=None
|
main=text_part=html_part=None
|
||||||
if text:
|
if text:
|
||||||
content, charset=text
|
content, charset=text
|
||||||
|
@ -234,7 +239,7 @@ def build_mail(text, html=None, attachments=[], embeddeds=[]):
|
||||||
|
|
||||||
return main
|
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
|
Fill in the From, To, Cc, Subject, Date and Message-Id I{headers} of
|
||||||
one existing message regarding the parameters.
|
one existing message regarding the parameters.
|
||||||
|
@ -312,6 +317,13 @@ def complete_mail(message, sender, recipients, subject, default_charset, cc=[],
|
||||||
else:
|
else:
|
||||||
return address
|
return address
|
||||||
|
|
||||||
|
if cc is None:
|
||||||
|
cc=[]
|
||||||
|
if bcc is None:
|
||||||
|
bcc=[]
|
||||||
|
if headers is None:
|
||||||
|
headers=[]
|
||||||
|
|
||||||
mail_from=getaddr(sender[1])
|
mail_from=getaddr(sender[1])
|
||||||
rcpt_to=list(map(getaddr, recipients))
|
rcpt_to=list(map(getaddr, recipients))
|
||||||
rcpt_to.extend(list(map(getaddr, cc)))
|
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
|
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
|
Compose an email regarding the arguments. Call L{build_mail()} and
|
||||||
L{complete_mail()} at once.
|
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')])
|
>>> 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)
|
message=build_mail(text, html, attachments, embeddeds)
|
||||||
return complete_mail(message, sender, recipients, subject, default_charset, cc, bcc, message_id_string, date, headers)
|
return complete_mail(message, sender, recipients, subject, default_charset, cc, bcc, message_id_string, date, headers)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue