Skip to content

Commit

Permalink
fix: avoid mutables as defaults. Compute date default arguments at ru…
Browse files Browse the repository at this point in the history
…ntime rather than loadtime. (ietf-tools#4144)
  • Loading branch information
rjsparks authored Jul 6, 2022
1 parent 75bb797 commit b988850
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 21 deletions.
6 changes: 5 additions & 1 deletion ietf/api/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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("_"):
Expand Down
14 changes: 10 additions & 4 deletions ietf/doc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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():
Expand All @@ -935,7 +939,9 @@ def get_predecessors(doc, predecessors=[]):
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():
Expand Down Expand Up @@ -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)
4 changes: 3 additions & 1 deletion ietf/nomcom/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
6 changes: 4 additions & 2 deletions ietf/person/templatetags/person_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@


@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)


Expand Down Expand Up @@ -88,4 +90,4 @@ def email_person_link(email, **kwargs):
"title": title,
"class": cls,
"with_email": with_email,
}
}
5 changes: 4 additions & 1 deletion ietf/review/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,13 @@ def days_needed_to_fulfill_min_interval_for_reviewers(team):
"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:
Expand Down
12 changes: 9 additions & 3 deletions ietf/stats/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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,
}
Expand Down
17 changes: 14 additions & 3 deletions ietf/utils/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 3 additions & 1 deletion ietf/utils/management/commands/sqldumpdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ def get_objects(self, app_list, pks, count_only=False):
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']
Expand Down
5 changes: 4 additions & 1 deletion ietf/utils/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1036,11 +1036,14 @@ def get_test_paths(self, test_labels):
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
Expand Down
2 changes: 1 addition & 1 deletion ietf/utils/test_smtpserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def handle_accept(self):
#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)


Expand Down
29 changes: 26 additions & 3 deletions pyzmail/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -312,6 +317,13 @@ def getaddr(address):
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)))
Expand Down Expand Up @@ -341,7 +353,7 @@ def getaddr(address):

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.
Expand All @@ -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', '[email protected]'), [(u'Him', '[email protected]')], 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)

Expand Down

0 comments on commit b988850

Please sign in to comment.