← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:py3-none-comparisons into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:py3-none-comparisons into launchpad:master.

Commit message:
Fix various problems comparing with None on Python 3

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/396857

On Python 3, attempting to compare None with other types of objects raises TypeError, so we need to be careful not to do so.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-none-comparisons into launchpad:master.
diff --git a/lib/lp/archivepublisher/model/ftparchive.py b/lib/lp/archivepublisher/model/ftparchive.py
index c516068..3203771 100644
--- a/lib/lp/archivepublisher/model/ftparchive.py
+++ b/lib/lp/archivepublisher/model/ftparchive.py
@@ -435,6 +435,7 @@ class FTPArchiveHandler:
                     package_arch = "%s/%s" % (packagename, archtag)
                     override['bin'].add((
                         package_arch, priority, section,
+                        0 if phased_update_percentage is None else 1,
                         phased_update_percentage))
                 elif subcomp in self.publisher.subcomponents:
                     # We pick up subcomponent packages here, although they
@@ -492,7 +493,7 @@ class FTPArchiveHandler:
         ef = open(ef_override_new, "w")
         f = open(main_override_new, "w")
         basic_override_seen = set()
-        for (package_arch, priority, section,
+        for (package_arch, priority, section, _,
              phased_update_percentage) in bin_overrides:
             package = package_arch.split("/")[0]
             if package not in basic_override_seen:
diff --git a/lib/lp/bugs/externalbugtracker/bugzilla.py b/lib/lp/bugs/externalbugtracker/bugzilla.py
index 43f8c74..9cd6ce3 100644
--- a/lib/lp/bugs/externalbugtracker/bugzilla.py
+++ b/lib/lp/bugs/externalbugtracker/bugzilla.py
@@ -379,7 +379,7 @@ class Bugzilla(ExternalBugTracker):
             resolution_tag = 'resolution'
             priority_tag = 'priority'
             severity_tag = None
-        elif self.version < (2, 16):
+        elif self.version is None or self.version < (2, 16):
             buglist_page = 'xml.cgi'
             data = {'id': ','.join(bug_ids)}
             bug_tag = 'bug'
diff --git a/lib/lp/code/templates/gitlisting.pt b/lib/lp/code/templates/gitlisting.pt
index 583deef..ed6c0eb 100644
--- a/lib/lp/code/templates/gitlisting.pt
+++ b/lib/lp/code/templates/gitlisting.pt
@@ -77,7 +77,7 @@ git push --set-upstream origin master
         <p id="active-review-count"
           tal:define="count context/menu:branches/active_review_count|nothing;
                       link context/menu:branches/active_reviews|nothing"
-          tal:condition="python: count &gt; 0">
+          tal:condition="python: count is not None and count &gt; 0">
           <tal:project replace="context/display_name"/> has
           <tal:active-count replace="count"/>
           <tal:link replace="structure python: link.render().lower()"/>.
diff --git a/lib/lp/registry/browser/poll.py b/lib/lp/registry/browser/poll.py
index c42bfb1..234139a 100644
--- a/lib/lp/registry/browser/poll.py
+++ b/lib/lp/registry/browser/poll.py
@@ -106,6 +106,15 @@ class PollNavigation(Navigation):
             self.context, int(name))
 
 
+def vote_sort_key(vote):
+    """A sort key for a vote.
+
+    Votes with preference=None come first, followed by all other votes in
+    ascending order of preference.
+    """
+    return (vote.preference is not None, vote.preference)
+
+
 class BasePollView(LaunchpadView):
     """A base view class to be used in other poll views."""
 
@@ -145,7 +154,7 @@ class BasePollView(LaunchpadView):
         elif self.isCondorcet():
             # Here we have multiple votes, and the token is the same in
             # all of them.
-            self.currentVotes = sorted(votes, key=lambda v: v.preference)
+            self.currentVotes = sorted(votes, key=vote_sort_key)
             self.token = self.currentVotes[0].token
         self.gotTokenAndVotes = True
 
@@ -186,7 +195,7 @@ class BasePollView(LaunchpadView):
             # option.
             self.currentVote = votes[0]
         elif self.isCondorcet():
-            self.currentVotes = sorted(votes, key=lambda v: v.preference)
+            self.currentVotes = sorted(votes, key=vote_sort_key)
         self.gotTokenAndVotes = True
         return True
 
@@ -371,13 +380,13 @@ class PollVoteView(BasePollView):
             assert len(activeoptions) == len(self.currentVotes)
             for vote in self.currentVotes:
                 vote.preference = newvotes.get(vote.option)
-            self.currentVotes.sort(key=lambda v: v.preference)
+            self.currentVotes.sort(key=vote_sort_key)
             self.feedback = "Your vote was changed successfully."
         else:
             # This is a new vote.
             votes = self.context.storeCondorcetVote(self.user, newvotes)
             self.token = votes[0].token
-            self.currentVotes = sorted(votes, key=lambda v: v.preference)
+            self.currentVotes = sorted(votes, key=vote_sort_key)
             if self.isSecret():
                 self.feedback = (
                     "Your vote has been recorded. If you want to view or "
diff --git a/lib/lp/services/timeout.py b/lib/lp/services/timeout.py
index 0feafae..6ba700c 100644
--- a/lib/lp/services/timeout.py
+++ b/lib/lp/services/timeout.py
@@ -376,6 +376,9 @@ class URLFetcher:
             request_kwargs.setdefault(
                 "verify", config.launchpad.ca_certificates_path)
         response = self.session.request(url=url, **request_kwargs)
+        if response.status_code is None:
+            raise HTTPError(
+                "HTTP request returned no status code", response=response)
         raise_for_status_redacted(response)
         if output_file is None:
             # Make sure the content has been consumed before returning.
diff --git a/lib/lp/translations/browser/person.py b/lib/lp/translations/browser/person.py
index e8f3e1d..5dbd804 100644
--- a/lib/lp/translations/browser/person.py
+++ b/lib/lp/translations/browser/person.py
@@ -324,7 +324,7 @@ class PersonTranslationView(LaunchpadView):
         Results are ordered from most to fewest untranslated messages.
         """
         person = ITranslationsPerson(self.context)
-        urgent_first = (max_fetch >= 0)
+        urgent_first = (max_fetch is not None and max_fetch >= 0)
         pofiles = person.getTranslatableFiles(
             no_older_than=self.history_horizon, urgent_first=urgent_first)
 
diff --git a/lib/lp/translations/model/pofile.py b/lib/lp/translations/model/pofile.py
index 799eb18..e7d2809 100644
--- a/lib/lp/translations/model/pofile.py
+++ b/lib/lp/translations/model/pofile.py
@@ -748,7 +748,8 @@ class POFile(SQLBase, POFileMixIn):
         query = [
             '%(table_name)s.msgstr0 IS NOT NULL' % {'table_name': table_name},
             ]
-        if self.language.pluralforms > 1:
+        if (self.language.pluralforms is not None and
+                self.language.pluralforms > 1):
             plurals_query = ' AND '.join(
                 '%(table_name)s.msgstr%(plural_form)d IS NOT NULL' % {
                   'plural_form': plural_form,
diff --git a/lib/lp/translations/utilities/gettext_po_parser.py b/lib/lp/translations/utilities/gettext_po_parser.py
index b961d0e..9245943 100644
--- a/lib/lp/translations/utilities/gettext_po_parser.py
+++ b/lib/lp/translations/utilities/gettext_po_parser.py
@@ -607,7 +607,8 @@ class POParser(object):
             number_plural_forms = (
                 self._translation_file.header.number_plural_forms)
             if (self._message.msgid_plural and
-                len(self._message.translations) < number_plural_forms):
+                    number_plural_forms is not None and
+                    len(self._message.translations) < number_plural_forms):
                 # Has plural forms but the number of translations is lower.
                 # Fill the others with an empty string.
                 for index in range(