Merge ~cjwatson/launchpad:pyupgrade-py3-app into launchpad:master
- Git
- lp:~cjwatson/launchpad
- pyupgrade-py3-app
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 26f156d81c2e13a700775ac2059086e3ead12572 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:pyupgrade-py3-app |
Merge into: | launchpad:master |
Diff against target: |
1864 lines (+226/-247) 44 files modified
.git-blame-ignore-revs (+4/-0) .pre-commit-config.yaml (+1/-1) lib/lp/app/browser/folder.py (+2/-3) lib/lp/app/browser/launchpad.py (+1/-1) lib/lp/app/browser/launchpadform.py (+1/-2) lib/lp/app/browser/lazrjs.py (+10/-11) lib/lp/app/browser/multistep.py (+3/-3) lib/lp/app/browser/root.py (+7/-8) lib/lp/app/browser/tales.py (+33/-35) lib/lp/app/browser/tests/test_base_layout.py (+2/-3) lib/lp/app/browser/tests/test_formatters.py (+8/-8) lib/lp/app/browser/tests/test_launchpad.py (+12/-14) lib/lp/app/browser/tests/test_launchpadform.py (+14/-14) lib/lp/app/browser/tests/test_launchpadroot.py (+1/-1) lib/lp/app/browser/tests/test_mixed_visibility.py (+1/-1) lib/lp/app/browser/tests/test_page_macro.py (+3/-3) lib/lp/app/browser/tests/test_stringformatter.py (+16/-16) lib/lp/app/browser/tests/test_vocabulary.py (+1/-1) lib/lp/app/browser/tests/test_webservice.py (+2/-2) lib/lp/app/browser/vocabulary.py (+7/-13) lib/lp/app/model/launchpad.py (+1/-1) lib/lp/app/security.py (+1/-1) lib/lp/app/services.py (+1/-1) lib/lp/app/tests/test_security.py (+1/-1) lib/lp/app/tests/test_tales.py (+3/-3) lib/lp/app/utilities/celebrities.py (+1/-1) lib/lp/app/validators/attachment.py (+2/-2) lib/lp/app/vocabularies.py (+1/-1) lib/lp/app/webservice/tests/test_marshallers.py (+4/-4) lib/lp/app/widgets/date.py (+3/-3) lib/lp/app/widgets/exception.py (+1/-1) lib/lp/app/widgets/itemswidgets.py (+24/-26) lib/lp/app/widgets/launchpadtarget.py (+3/-3) lib/lp/app/widgets/owner.py (+1/-1) lib/lp/app/widgets/popup.py (+4/-6) lib/lp/app/widgets/product.py (+9/-11) lib/lp/app/widgets/project.py (+2/-2) lib/lp/app/widgets/suggestion.py (+10/-10) lib/lp/app/widgets/tests/test_datetime.py (+2/-2) lib/lp/app/widgets/tests/test_itemswidgets.py (+2/-2) lib/lp/app/widgets/tests/test_launchpadtarget.py (+4/-5) lib/lp/app/widgets/tests/test_popup.py (+2/-2) lib/lp/app/widgets/tests/test_suggestion.py (+4/-4) lib/lp/app/widgets/textwidgets.py (+11/-14) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+412212@code.launchpad.net |
Commit message
lp.app: Apply "pyupgrade --py3-plus"
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs |
2 | index 2cb1da8..6115e5c 100644 |
3 | --- a/.git-blame-ignore-revs |
4 | +++ b/.git-blame-ignore-revs |
5 | @@ -1,2 +1,6 @@ |
6 | # apply pyupgrade |
7 | 67e3b53a4375288983a72a7beb9a5a67ba739527 |
8 | +# apply pyupgrade --py3-plus to lp.answers |
9 | +5d46ca0970916c2b161761aee29f46419dd3efea |
10 | +# apply pyupgrade --py3-plus to lp.app |
11 | +7fbeaae55d7d282ccda47c76a27c879e04ee14e9 |
12 | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml |
13 | index 34ba814..162ad2f 100644 |
14 | --- a/.pre-commit-config.yaml |
15 | +++ b/.pre-commit-config.yaml |
16 | @@ -38,7 +38,7 @@ repos: |
17 | alias: pyupgrade-py3 |
18 | name: pyupgrade (--py3-plus) |
19 | args: [--keep-percent-format, --py3-plus] |
20 | - files: ^lib/lp/answers/ |
21 | + files: ^lib/lp/(answers|app)/ |
22 | - repo: https://github.com/PyCQA/isort |
23 | rev: 5.9.2 |
24 | hooks: |
25 | diff --git a/lib/lp/app/browser/folder.py b/lib/lp/app/browser/folder.py |
26 | index 8c8c9ac..d38a5be 100644 |
27 | --- a/lib/lp/app/browser/folder.py |
28 | +++ b/lib/lp/app/browser/folder.py |
29 | @@ -85,7 +85,7 @@ class ExportedFolder: |
30 | name = os.path.basename(filename) |
31 | try: |
32 | fileobj = File(filename, name) |
33 | - except IOError as ioerror: |
34 | + except OSError as ioerror: |
35 | expected = (errno.ENOENT, errno.EISDIR, errno.ENOTDIR) |
36 | if ioerror.errno in expected: |
37 | # No such file or is a directory. |
38 | @@ -147,5 +147,4 @@ class ExportedImageFolder(ExportedFolder): |
39 | if os.path.exists(root + image_ext): |
40 | filename = filename + image_ext |
41 | break |
42 | - return super( |
43 | - ExportedImageFolder, self).prepareDataForServing(filename) |
44 | + return super().prepareDataForServing(filename) |
45 | diff --git a/lib/lp/app/browser/launchpad.py b/lib/lp/app/browser/launchpad.py |
46 | index 6c5045f..110a34a 100644 |
47 | --- a/lib/lp/app/browser/launchpad.py |
48 | +++ b/lib/lp/app/browser/launchpad.py |
49 | @@ -1105,7 +1105,7 @@ class LaunchpadTourFolder(ExportedFolder): |
50 | """ |
51 | if name == 'source': |
52 | raise NotFound(request, name) |
53 | - return super(LaunchpadTourFolder, self).publishTraverse(request, name) |
54 | + return super().publishTraverse(request, name) |
55 | |
56 | def browserDefault(self, request): |
57 | """Redirect to index.html if the directory itself is requested.""" |
58 | diff --git a/lib/lp/app/browser/launchpadform.py b/lib/lp/app/browser/launchpadform.py |
59 | index 642f044..220b013 100644 |
60 | --- a/lib/lp/app/browser/launchpadform.py |
61 | +++ b/lib/lp/app/browser/launchpadform.py |
62 | @@ -17,7 +17,6 @@ __all__ = [ |
63 | from lazr.lifecycle.event import ObjectModifiedEvent |
64 | from lazr.lifecycle.snapshot import Snapshot |
65 | import simplejson |
66 | -import six |
67 | import transaction |
68 | from zope.event import notify |
69 | from zope.formlib import form |
70 | @@ -212,7 +211,7 @@ class LaunchpadFormView(LaunchpadView): |
71 | self.form_fields, self.prefix, context, self.request, |
72 | data=self.initial_values, adapters=self.adapters, |
73 | ignore_request=False) |
74 | - for field_name, help_link in six.iteritems(self.help_links): |
75 | + for field_name, help_link in self.help_links.items(): |
76 | self.widgets[field_name].help_link = help_link |
77 | |
78 | @property |
79 | diff --git a/lib/lp/app/browser/lazrjs.py b/lib/lp/app/browser/lazrjs.py |
80 | index 51c22da..1d4a85f 100644 |
81 | --- a/lib/lp/app/browser/lazrjs.py |
82 | +++ b/lib/lp/app/browser/lazrjs.py |
83 | @@ -22,7 +22,6 @@ from lazr.restful.utils import ( |
84 | safe_hasattr, |
85 | ) |
86 | import simplejson |
87 | -import six |
88 | from zope.browserpage import ViewPageTemplateFile |
89 | from zope.component import getUtility |
90 | from zope.schema.interfaces import ( |
91 | @@ -119,7 +118,7 @@ class TextWidgetBase(WidgetBase): |
92 | |
93 | def __init__(self, context, exported_field, title, content_box_id, |
94 | edit_view, edit_url, edit_title): |
95 | - super(TextWidgetBase, self).__init__( |
96 | + super().__init__( |
97 | context, exported_field, content_box_id, |
98 | edit_view, edit_url, edit_title) |
99 | self.accept_empty = simplejson.dumps(self.optional_field) |
100 | @@ -181,7 +180,7 @@ class TextLineEditorWidget(TextWidgetBase, DefinedTagMixin): |
101 | field value instead of the attribute's current value. |
102 | :param width: Initial widget width. |
103 | """ |
104 | - super(TextLineEditorWidget, self).__init__( |
105 | + super().__init__( |
106 | context, exported_field, title, content_box_id, |
107 | edit_view, edit_url, edit_title) |
108 | self.tag = tag |
109 | @@ -242,7 +241,7 @@ class TextAreaEditorWidget(TextWidgetBase): |
110 | :param linkify_text: If True the HTML version of the text will have |
111 | things that look like links made into anchors. |
112 | """ |
113 | - super(TextAreaEditorWidget, self).__init__( |
114 | + super().__init__( |
115 | context, exported_field, title, content_box_id, |
116 | edit_view, edit_url, edit_title) |
117 | self.hide_empty = hide_empty |
118 | @@ -294,7 +293,7 @@ class InlineEditPickerWidget(WidgetBase): |
119 | in and when JS is off. Defaults to the edit_view on the context. |
120 | :param edit_title: Used to set the title attribute of the anchor. |
121 | """ |
122 | - super(InlineEditPickerWidget, self).__init__( |
123 | + super().__init__( |
124 | context, exported_field, content_box_id, |
125 | edit_view, edit_url, edit_title) |
126 | self.default_html = default_html |
127 | @@ -394,7 +393,7 @@ class InlinePersonEditPickerWidget(InlineEditPickerWidget): |
128 | :param edit_title: Used to set the title attribute of the anchor. |
129 | :param help_link: Used to set a link for help for the widget. |
130 | """ |
131 | - super(InlinePersonEditPickerWidget, self).__init__( |
132 | + super().__init__( |
133 | context, exported_field, default_html, content_box_id, header, |
134 | step_title, null_display_value, |
135 | edit_view, edit_url, edit_title, help_link) |
136 | @@ -425,7 +424,7 @@ class InlinePersonEditPickerWidget(InlineEditPickerWidget): |
137 | return self._show_create_team |
138 | |
139 | def getConfig(self): |
140 | - config = super(InlinePersonEditPickerWidget, self).getConfig() |
141 | + config = super().getConfig() |
142 | config.update(dict( |
143 | show_remove_button=self.optional_field, |
144 | show_assign_me_button=self.show_assign_me_button, |
145 | @@ -477,7 +476,7 @@ class InlineMultiCheckboxWidget(WidgetBase): |
146 | :param edit_title: Used to set the title attribute of the anchor. |
147 | |
148 | """ |
149 | - super(InlineMultiCheckboxWidget, self).__init__( |
150 | + super().__init__( |
151 | context, exported_field, content_box_id, |
152 | edit_view, edit_url, edit_title) |
153 | |
154 | @@ -502,7 +501,7 @@ class InlineMultiCheckboxWidget(WidgetBase): |
155 | else: |
156 | vocabulary = exported_field.vocabularyName |
157 | |
158 | - if isinstance(vocabulary, six.string_types): |
159 | + if isinstance(vocabulary, str): |
160 | vocabulary = getVocabularyRegistry().get(context, vocabulary) |
161 | |
162 | # Construct checkbox data dict for each item in the vocabulary. |
163 | @@ -638,7 +637,7 @@ class BooleanChoiceWidget(WidgetBase, DefinedTagMixin): |
164 | Automatically generated if this is not provided. |
165 | :param header: The large text at the top of the choice popup. |
166 | """ |
167 | - super(BooleanChoiceWidget, self).__init__( |
168 | + super().__init__( |
169 | context, exported_field, content_box_id, |
170 | edit_view, edit_url, edit_title) |
171 | self.header = header |
172 | @@ -698,7 +697,7 @@ class EnumChoiceWidget(WidgetBase): |
173 | :param edit_title: Used to set the title attribute of the anchor. |
174 | :param css_class_prefix: Added to the start of the enum titles. |
175 | """ |
176 | - super(EnumChoiceWidget, self).__init__( |
177 | + super().__init__( |
178 | context, exported_field, content_box_id, |
179 | edit_view, edit_url, edit_title) |
180 | self.header = header |
181 | diff --git a/lib/lp/app/browser/multistep.py b/lib/lp/app/browser/multistep.py |
182 | index 278f8e1..6215eca 100644 |
183 | --- a/lib/lp/app/browser/multistep.py |
184 | +++ b/lib/lp/app/browser/multistep.py |
185 | @@ -152,7 +152,7 @@ class StepView(LaunchpadFormView): |
186 | |
187 | _field_names = [] |
188 | step_name = '' |
189 | - main_action_label = u'Continue' |
190 | + main_action_label = 'Continue' |
191 | next_step = None |
192 | |
193 | # Step information. These get filled in by the controller view. |
194 | @@ -201,7 +201,7 @@ class StepView(LaunchpadFormView): |
195 | `validateStep()` if they have any custom validation they need to |
196 | perform. |
197 | """ |
198 | - super(StepView, self).validate(data) |
199 | + super().validate(data) |
200 | if self.shouldProcess(data): |
201 | self.validateStep(data) |
202 | |
203 | @@ -243,7 +243,7 @@ class StepView(LaunchpadFormView): |
204 | operation.label = self.main_action_label |
205 | actions.append(operation) |
206 | self.actions = actions |
207 | - return super(StepView, self).render() |
208 | + return super().render() |
209 | |
210 | @property |
211 | def cancel_url(self): |
212 | diff --git a/lib/lp/app/browser/root.py b/lib/lp/app/browser/root.py |
213 | index f0e85f7..694c8d2 100644 |
214 | --- a/lib/lp/app/browser/root.py |
215 | +++ b/lib/lp/app/browser/root.py |
216 | @@ -14,7 +14,6 @@ import time |
217 | import feedparser |
218 | from lazr.batchnavigator.z3batching import batch |
219 | import requests |
220 | -import six |
221 | from zope.component import getUtility |
222 | from zope.formlib.interfaces import ConversionError |
223 | from zope.interface import Interface |
224 | @@ -79,7 +78,7 @@ class LaunchpadRootIndexView(HasAnnouncementsView, LaunchpadView): |
225 | |
226 | def initialize(self): |
227 | """Set up featured projects list and the top featured project.""" |
228 | - super(LaunchpadRootIndexView, self).initialize() |
229 | + super().initialize() |
230 | # The maximum number of projects to be displayed as defined by the |
231 | # number of items plus one top featured project. |
232 | self.featured_projects = list( |
233 | @@ -275,7 +274,7 @@ class LaunchpadSearchView(LaunchpadFormView): |
234 | |
235 | Set the state of the search_params and matches. |
236 | """ |
237 | - super(LaunchpadSearchView, self).__init__(context, request) |
238 | + super().__init__(context, request) |
239 | self.has_page_service = True |
240 | self._bug = None |
241 | self._question = None |
242 | @@ -346,7 +345,7 @@ class LaunchpadSearchView(LaunchpadFormView): |
243 | """Focus the first widget when there are no matches.""" |
244 | if self.has_matches: |
245 | return None |
246 | - return super(LaunchpadSearchView, self).focusedElementScript() |
247 | + return super().focusedElementScript() |
248 | |
249 | @property |
250 | def bug(self): |
251 | @@ -427,7 +426,7 @@ class LaunchpadSearchView(LaunchpadFormView): |
252 | if isinstance(error, ConversionError): |
253 | self.setFieldError( |
254 | 'text', 'Can not convert your search term.') |
255 | - elif isinstance(error, six.text_type): |
256 | + elif isinstance(error, str): |
257 | continue |
258 | elif (error.field_name == 'text' |
259 | and isinstance(error.errors, TooLong)): |
260 | @@ -435,7 +434,7 @@ class LaunchpadSearchView(LaunchpadFormView): |
261 | 'text', 'The search text cannot exceed 250 characters.') |
262 | |
263 | @safe_action |
264 | - @action(u'Search', name='search') |
265 | + @action('Search', name='search') |
266 | def search_action(self, action, data): |
267 | """The Action executed when the user uses the search button. |
268 | |
269 | @@ -579,7 +578,7 @@ class WindowedListBatch(batch._Batch): |
270 | |
271 | def __iter__(self): |
272 | """Iterate over objects that are not None.""" |
273 | - for item in super(WindowedListBatch, self).__iter__(): |
274 | + for item in super().__iter__(): |
275 | if item is not None: |
276 | # Never yield None |
277 | yield item |
278 | @@ -614,7 +613,7 @@ class SiteSearchBatchNavigator(BatchNavigator): |
279 | :param callback: Not used. |
280 | """ |
281 | results = WindowedList(results, start, results.total) |
282 | - super(SiteSearchBatchNavigator, self).__init__(results, request, |
283 | + super().__init__(results, request, |
284 | start=start, size=size, callback=callback, |
285 | transient_parameters=transient_parameters, |
286 | force_start=force_start, range_factory=range_factory) |
287 | diff --git a/lib/lp/app/browser/tales.py b/lib/lp/app/browser/tales.py |
288 | index 08d2a71..905ba0d 100644 |
289 | --- a/lib/lp/app/browser/tales.py |
290 | +++ b/lib/lp/app/browser/tales.py |
291 | @@ -21,7 +21,6 @@ from lazr.enum import enumerated_type_registry |
292 | from lazr.restful.utils import get_current_browser_request |
293 | from lazr.uri import URI |
294 | import pytz |
295 | -import six |
296 | from six.moves.urllib.parse import quote |
297 | from zope.browserpage import ViewPageTemplateFile |
298 | from zope.component import ( |
299 | @@ -688,9 +687,9 @@ class ObjectFormatterAPI: |
300 | text = breadcrumb.detail |
301 | if len(text) > 64: |
302 | truncated = '%s...' % text[0:64] |
303 | - if truncated.count(u'\u201c') > truncated.count(u'\u201cd'): |
304 | + if truncated.count('\u201c') > truncated.count('\u201cd'): |
305 | # Close the open smartquote if it was dropped. |
306 | - truncated += u'\u201d' |
307 | + truncated += '\u201d' |
308 | return truncated |
309 | return text |
310 | |
311 | @@ -1252,7 +1251,7 @@ class PersonFormatterAPI(ObjectFormatterAPI): |
312 | |
313 | The default URL for a person is to the mainsite. |
314 | """ |
315 | - return super(PersonFormatterAPI, self).url(view_name, rootsite) |
316 | + return super().url(view_name, rootsite) |
317 | |
318 | def _makeLink(self, view_name, rootsite, text): |
319 | person = self._context |
320 | @@ -1315,7 +1314,7 @@ class MixedVisibilityError(Exception): |
321 | class TeamFormatterAPI(PersonFormatterAPI): |
322 | """Adapter for `ITeam` objects to a formatted string.""" |
323 | |
324 | - hidden = u'<hidden>' |
325 | + hidden = '<hidden>' |
326 | |
327 | def url(self, view_name=None, rootsite='mainsite'): |
328 | """See `ObjectFormatterAPI`. |
329 | @@ -1327,7 +1326,7 @@ class TeamFormatterAPI(PersonFormatterAPI): |
330 | # This person has no permission to view the team details. |
331 | self._report_visibility_leak() |
332 | return None |
333 | - return super(TeamFormatterAPI, self).url(view_name, rootsite) |
334 | + return super().url(view_name, rootsite) |
335 | |
336 | def api_url(self, context): |
337 | """See `ObjectFormatterAPI`.""" |
338 | @@ -1335,7 +1334,7 @@ class TeamFormatterAPI(PersonFormatterAPI): |
339 | # This person has no permission to view the team details. |
340 | self._report_visibility_leak() |
341 | return None |
342 | - return super(TeamFormatterAPI, self).api_url(context) |
343 | + return super().api_url(context) |
344 | |
345 | def link(self, view_name, rootsite='mainsite'): |
346 | """See `ObjectFormatterAPI`. |
347 | @@ -1349,7 +1348,7 @@ class TeamFormatterAPI(PersonFormatterAPI): |
348 | self._report_visibility_leak() |
349 | return structured( |
350 | '<span class="sprite team">%s</span>', self.hidden).escapedtext |
351 | - return super(TeamFormatterAPI, self).link(view_name, rootsite) |
352 | + return super().link(view_name, rootsite) |
353 | |
354 | def icon(self, view_name): |
355 | team = self._context |
356 | @@ -1357,7 +1356,7 @@ class TeamFormatterAPI(PersonFormatterAPI): |
357 | css_class = ObjectImageDisplayAPI(team).sprite_css() |
358 | return '<span class="' + css_class + '"></span>' |
359 | else: |
360 | - return super(TeamFormatterAPI, self).icon(view_name) |
361 | + return super().icon(view_name) |
362 | |
363 | def displayname(self, view_name, rootsite=None): |
364 | """See `PersonFormatterAPI`.""" |
365 | @@ -1366,7 +1365,7 @@ class TeamFormatterAPI(PersonFormatterAPI): |
366 | # This person has no permission to view the team details. |
367 | self._report_visibility_leak() |
368 | return self.hidden |
369 | - return super(TeamFormatterAPI, self).displayname(view_name, rootsite) |
370 | + return super().displayname(view_name, rootsite) |
371 | |
372 | def unique_displayname(self, view_name): |
373 | """See `PersonFormatterAPI`.""" |
374 | @@ -1375,7 +1374,7 @@ class TeamFormatterAPI(PersonFormatterAPI): |
375 | # This person has no permission to view the team details. |
376 | self._report_visibility_leak() |
377 | return self.hidden |
378 | - return super(TeamFormatterAPI, self).unique_displayname(view_name) |
379 | + return super().unique_displayname(view_name) |
380 | |
381 | def _report_visibility_leak(self): |
382 | request = get_current_browser_request() |
383 | @@ -1426,7 +1425,7 @@ class CustomizableFormatter(ObjectFormatterAPI): |
384 | """ |
385 | values = { |
386 | k: v if v is not None else '' |
387 | - for k, v in six.iteritems(self._link_summary_values())} |
388 | + for k, v in self._link_summary_values().items()} |
389 | return structured(self._link_summary_template, **values).escapedtext |
390 | |
391 | def _title_values(self): |
392 | @@ -1448,7 +1447,7 @@ class CustomizableFormatter(ObjectFormatterAPI): |
393 | return None |
394 | values = { |
395 | k: v if v is not None else '' |
396 | - for k, v in six.iteritems(self._title_values())} |
397 | + for k, v in self._title_values().items()} |
398 | return structured(title_template, **values).escapedtext |
399 | |
400 | def sprite_css(self): |
401 | @@ -1512,7 +1511,7 @@ class PillarFormatterAPI(CustomizableFormatter): |
402 | |
403 | The default URL for a pillar is to the mainsite. |
404 | """ |
405 | - return super(PillarFormatterAPI, self).url(view_name, rootsite) |
406 | + return super().url(view_name, rootsite) |
407 | |
408 | def _getLinkHTML(self, view_name, rootsite, |
409 | template, custom_icon_template): |
410 | @@ -1550,11 +1549,11 @@ class PillarFormatterAPI(CustomizableFormatter): |
411 | In the case of Products or ProjectGroups we display the custom |
412 | icon, if one exists. The default URL for a pillar is to the mainsite. |
413 | """ |
414 | - super(PillarFormatterAPI, self).link(view_name) |
415 | - template = u'<a href="%(url)s" class="%(css_class)s">%(summary)s</a>' |
416 | + super().link(view_name) |
417 | + template = '<a href="%(url)s" class="%(css_class)s">%(summary)s</a>' |
418 | custom_icon_template = ( |
419 | - u'<a href="%(url)s" class="bg-image" ' |
420 | - u'style="background-image: url(%(custom_icon)s)">%(summary)s</a>' |
421 | + '<a href="%(url)s" class="bg-image" ' |
422 | + 'style="background-image: url(%(custom_icon)s)">%(summary)s</a>' |
423 | ) |
424 | return self._getLinkHTML( |
425 | view_name, rootsite, template, custom_icon_template) |
426 | @@ -1566,15 +1565,15 @@ class PillarFormatterAPI(CustomizableFormatter): |
427 | In the case of Products or ProjectGroups we display the custom |
428 | icon, if one exists. The default URL for a pillar is to the mainsite. |
429 | """ |
430 | - super(PillarFormatterAPI, self).link(view_name) |
431 | + super().link(view_name) |
432 | template = ( |
433 | - u'<a href="%(url)s" class="%(css_class)s">%(displayname)s</a>' |
434 | - u' (<a href="%(url)s">%(name)s</a>)' |
435 | + '<a href="%(url)s" class="%(css_class)s">%(displayname)s</a>' |
436 | + ' (<a href="%(url)s">%(name)s</a>)' |
437 | ) |
438 | custom_icon_template = ( |
439 | - u'<a href="%(url)s" class="bg-image" ' |
440 | - u'style="background-image: url(%(custom_icon)s)">' |
441 | - u'%(displayname)s</a> (<a href="%(url)s">%(name)s</a>)' |
442 | + '<a href="%(url)s" class="bg-image" ' |
443 | + 'style="background-image: url(%(custom_icon)s)">' |
444 | + '%(displayname)s</a> (<a href="%(url)s">%(name)s</a>)' |
445 | ) |
446 | return self._getLinkHTML( |
447 | view_name, rootsite, template, custom_icon_template) |
448 | @@ -1739,7 +1738,7 @@ class GitRefFormatterAPI(CustomizableFormatter): |
449 | """ |
450 | if self._context.repository_url is not None: |
451 | return None |
452 | - return super(GitRefFormatterAPI, self).url(view_name, rootsite) |
453 | + return super().url(view_name, rootsite) |
454 | |
455 | def _link_summary_values(self): |
456 | return {'display_name': self._context.display_name} |
457 | @@ -2085,7 +2084,7 @@ class BugTrackerFormatterAPI(ObjectFormatterAPI): |
458 | """ |
459 | url = self._context.baseurl |
460 | if url.startswith('mailto:') and getUtility(ILaunchBag).user is None: |
461 | - return html_escape(u'mailto:<email address hidden>') |
462 | + return html_escape('mailto:<email address hidden>') |
463 | else: |
464 | return structured( |
465 | '<a class="link-external" href="%(url)s">%(url)s</a>', |
466 | @@ -2118,7 +2117,7 @@ class BugTrackerFormatterAPI(ObjectFormatterAPI): |
467 | anonymous = getUtility(ILaunchBag).user is None |
468 | for alias in self._context.aliases: |
469 | if anonymous and alias.startswith('mailto:'): |
470 | - yield u'mailto:<email address hidden>' |
471 | + yield 'mailto:<email address hidden>' |
472 | else: |
473 | yield alias |
474 | |
475 | @@ -2141,7 +2140,7 @@ class BugWatchFormatterAPI(ObjectFormatterAPI): |
476 | an email address, only the summary is returned (i.e. no link). |
477 | """ |
478 | if summary is None or len(summary) == 0: |
479 | - summary = structured(u'—') |
480 | + summary = structured('—') |
481 | url = self._context.url |
482 | if url.startswith('mailto:') and getUtility(ILaunchBag).user is None: |
483 | return html_escape(summary) |
484 | @@ -2159,7 +2158,7 @@ class BugWatchFormatterAPI(ObjectFormatterAPI): |
485 | summary = self._context.bugtracker.name |
486 | remotebug = self._context.remotebug |
487 | if remotebug is not None and len(remotebug) > 0: |
488 | - summary = u'%s #%s' % (summary, remotebug) |
489 | + summary = '%s #%s' % (summary, remotebug) |
490 | return self._make_external_link(summary) |
491 | |
492 | def external_link_short(self): |
493 | @@ -2584,7 +2583,7 @@ class LinkFormatterAPI(ObjectFormatterAPI): |
494 | if self._context.enabled: |
495 | return self._context.url |
496 | else: |
497 | - return u'' |
498 | + return '' |
499 | |
500 | |
501 | class RevisionAuthorFormatterAPI(ObjectFormatterAPI): |
502 | @@ -2629,7 +2628,7 @@ class PermissionRequiredQuery: |
503 | |
504 | |
505 | class IMainTemplateFile(Interface): |
506 | - path = TextLine(title=u'The absolute path to this main template.') |
507 | + path = TextLine(title='The absolute path to this main template.') |
508 | |
509 | |
510 | @adapter(LaunchpadLayer) |
511 | @@ -2776,8 +2775,7 @@ class TranslationGroupFormatterAPI(ObjectFormatterAPI): |
512 | |
513 | def url(self, view_name=None, rootsite='translations'): |
514 | """See `ObjectFormatterAPI`.""" |
515 | - return super(TranslationGroupFormatterAPI, self).url( |
516 | - view_name, rootsite) |
517 | + return super().url(view_name, rootsite) |
518 | |
519 | def link(self, view_name, rootsite='translations'): |
520 | """See `ObjectFormatterAPI`.""" |
521 | @@ -2800,7 +2798,7 @@ class LanguageFormatterAPI(ObjectFormatterAPI): |
522 | |
523 | def url(self, view_name=None, rootsite='translations'): |
524 | """See `ObjectFormatterAPI`.""" |
525 | - return super(LanguageFormatterAPI, self).url(view_name, rootsite) |
526 | + return super().url(view_name, rootsite) |
527 | |
528 | def link(self, view_name, rootsite='translations'): |
529 | """See `ObjectFormatterAPI`.""" |
530 | @@ -2825,7 +2823,7 @@ class POFileFormatterAPI(ObjectFormatterAPI): |
531 | |
532 | def url(self, view_name=None, rootsite='translations'): |
533 | """See `ObjectFormatterAPI`.""" |
534 | - return super(POFileFormatterAPI, self).url(view_name, rootsite) |
535 | + return super().url(view_name, rootsite) |
536 | |
537 | def link(self, view_name, rootsite='translations'): |
538 | """See `ObjectFormatterAPI`.""" |
539 | diff --git a/lib/lp/app/browser/tests/test_base_layout.py b/lib/lp/app/browser/tests/test_base_layout.py |
540 | index 1cbdaa6..d3c0c0b 100644 |
541 | --- a/lib/lp/app/browser/tests/test_base_layout.py |
542 | +++ b/lib/lp/app/browser/tests/test_base_layout.py |
543 | @@ -34,7 +34,7 @@ class TestBaseLayout(TestCaseWithFactory): |
544 | layer = DatabaseFunctionalLayer |
545 | |
546 | def setUp(self): |
547 | - super(TestBaseLayout, self).setUp() |
548 | + super().setUp() |
549 | self.user = self.factory.makePerson(name='waffles') |
550 | self.context = None |
551 | |
552 | @@ -116,8 +116,7 @@ class TestBaseLayout(TestCaseWithFactory): |
553 | self.assertEqual(['watermark-apps-portlet'], watermark['class']) |
554 | if self.context.is_team: |
555 | self.assertEqual('/@@/team-logo', watermark.img['src']) |
556 | - self.assertEqual( |
557 | - u'\u201cWaffles\u201d team', watermark.h2.a.string) |
558 | + self.assertEqual('\u201cWaffles\u201d team', watermark.h2.a.string) |
559 | else: |
560 | self.assertEqual('/@@/person-logo', watermark.img['src']) |
561 | self.assertEqual('Waffles', watermark.h2.a.string) |
562 | diff --git a/lib/lp/app/browser/tests/test_formatters.py b/lib/lp/app/browser/tests/test_formatters.py |
563 | index 25f355c..c917b5e 100644 |
564 | --- a/lib/lp/app/browser/tests/test_formatters.py |
565 | +++ b/lib/lp/app/browser/tests/test_formatters.py |
566 | @@ -64,7 +64,7 @@ class ObjectFormatterAPITestCase(TestCaseWithFactory, FakeAdapterMixin): |
567 | view.request.traversed_objects = [project, bug.bugtasks[0], view] |
568 | formatter = ObjectFormatterAPI(view) |
569 | self.assertEqual( |
570 | - u'%s \u201cbang\u201d : Bugs : Fnord' % bug.displayname, |
571 | + '%s \u201cbang\u201d : Bugs : Fnord' % bug.displayname, |
572 | formatter.pagetitle()) |
573 | |
574 | def test_pagetitle_last_breadcrumb_detail_too_long(self): |
575 | @@ -76,8 +76,8 @@ class ObjectFormatterAPITestCase(TestCaseWithFactory, FakeAdapterMixin): |
576 | current_request=True, server_url='https://bugs.launchpad.test/') |
577 | view.request.traversed_objects = [project, bug.bugtasks[0], view] |
578 | formatter = ObjectFormatterAPI(view) |
579 | - detail = u'%s \u201c%s\u201d' % (bug.displayname, title) |
580 | - expected_title = u'%s...\u201d : Bugs : Fnord' % detail[0:64] |
581 | + detail = '%s \u201c%s\u201d' % (bug.displayname, title) |
582 | + expected_title = '%s...\u201d : Bugs : Fnord' % detail[0:64] |
583 | self.assertEqual(expected_title, formatter.pagetitle()) |
584 | |
585 | def test_global_css(self): |
586 | @@ -97,10 +97,10 @@ class TestPillarFormatterAPI(TestCaseWithFactory): |
587 | |
588 | layer = DatabaseFunctionalLayer |
589 | |
590 | - FORMATTER_CSS_CLASS = u'sprite product' |
591 | + FORMATTER_CSS_CLASS = 'sprite product' |
592 | |
593 | def setUp(self): |
594 | - super(TestPillarFormatterAPI, self).setUp() |
595 | + super().setUp() |
596 | self.product = self.factory.makeProduct() |
597 | self.formatter = PillarFormatterAPI(self.product) |
598 | self.product_url = canonical_url( |
599 | @@ -111,7 +111,7 @@ class TestPillarFormatterAPI(TestCaseWithFactory): |
600 | # current context, formatted to include a custom icon if the |
601 | # context has one, and to display the context summary. |
602 | link = self.formatter.link(None) |
603 | - template = u'<a href="%(url)s" class="%(css_class)s">%(summary)s</a>' |
604 | + template = '<a href="%(url)s" class="%(css_class)s">%(summary)s</a>' |
605 | mapping = { |
606 | 'url': self.product_url, |
607 | 'summary': self.product.displayname, |
608 | @@ -126,8 +126,8 @@ class TestPillarFormatterAPI(TestCaseWithFactory): |
609 | # (displayname and name of the context). |
610 | link = self.formatter.link_with_displayname(None) |
611 | template = ( |
612 | - u'<a href="%(url)s" class="%(css_class)s">%(summary)s</a>' |
613 | - u' (<a href="%(url)s">%(name)s</a>)' |
614 | + '<a href="%(url)s" class="%(css_class)s">%(summary)s</a>' |
615 | + ' (<a href="%(url)s">%(name)s</a>)' |
616 | ) |
617 | mapping = { |
618 | 'url': self.product_url, |
619 | diff --git a/lib/lp/app/browser/tests/test_launchpad.py b/lib/lp/app/browser/tests/test_launchpad.py |
620 | index dc697fd..3b2ceaa 100644 |
621 | --- a/lib/lp/app/browser/tests/test_launchpad.py |
622 | +++ b/lib/lp/app/browser/tests/test_launchpad.py |
623 | @@ -167,8 +167,7 @@ class TestBranchTraversal(TestCaseWithFactory, TraversalMixin): |
624 | path, notification, BrowserNotificationLevel.ERROR) |
625 | |
626 | def traverse(self, path, **kwargs): |
627 | - return super(TestBranchTraversal, self).traverse( |
628 | - path, '+branch', **kwargs) |
629 | + return super().traverse(path, '+branch', **kwargs) |
630 | |
631 | def test_unique_name_traversal(self): |
632 | # Traversing to /+branch/<unique_name> redirects to the page for that |
633 | @@ -216,14 +215,14 @@ class TestBranchTraversal(TestCaseWithFactory, TraversalMixin): |
634 | InformationType.USERDATA) |
635 | login(ANONYMOUS) |
636 | requiredMessage = ( |
637 | - u"The target %s does not have a linked branch." % |
638 | + "The target %s does not have a linked branch." % |
639 | naked_product.name) |
640 | self.assertDisplaysNotice(naked_product.name, requiredMessage) |
641 | |
642 | def test_nonexistent_product(self): |
643 | # Traversing to /+branch/<no-such-product> displays an error message. |
644 | non_existent = 'non-existent' |
645 | - required_message = u"No such product: '%s'." % non_existent |
646 | + required_message = "No such product: '%s'." % non_existent |
647 | self.assertDisplaysError(non_existent, html_escape(required_message)) |
648 | |
649 | def test_nonexistent_product_without_referer(self): |
650 | @@ -249,7 +248,7 @@ class TestBranchTraversal(TestCaseWithFactory, TraversalMixin): |
651 | # user message on the same page. |
652 | product = self.factory.makeProduct() |
653 | requiredMessage = ( |
654 | - u"The target %s does not have a linked branch." % product.name) |
655 | + "The target %s does not have a linked branch." % product.name) |
656 | self.assertDisplaysNotice(product.name, requiredMessage) |
657 | |
658 | def test_distro_package_alias(self): |
659 | @@ -279,7 +278,7 @@ class TestBranchTraversal(TestCaseWithFactory, TraversalMixin): |
660 | login(ANONYMOUS) |
661 | path = ICanHasLinkedBranch(distro_package).bzr_path |
662 | requiredMessage = ( |
663 | - u"The target %s does not have a linked branch." % path) |
664 | + "The target %s does not have a linked branch." % path) |
665 | self.assertDisplaysNotice(path, requiredMessage) |
666 | |
667 | def test_trailing_path_redirect(self): |
668 | @@ -323,7 +322,7 @@ class TestBranchTraversal(TestCaseWithFactory, TraversalMixin): |
669 | login(ANONYMOUS) |
670 | path = ICanHasLinkedBranch(series).bzr_path |
671 | requiredMessage = ( |
672 | - u"The target %s does not have a linked branch." % path) |
673 | + "The target %s does not have a linked branch." % path) |
674 | self.assertDisplaysNotice(path, requiredMessage) |
675 | |
676 | def test_too_short_branch_name(self): |
677 | @@ -331,13 +330,13 @@ class TestBranchTraversal(TestCaseWithFactory, TraversalMixin): |
678 | # that's too short to be a real unique name. |
679 | owner = self.factory.makePerson() |
680 | requiredMessage = html_escape( |
681 | - u"Cannot understand namespace name: '%s'" % owner.name) |
682 | + "Cannot understand namespace name: '%s'" % owner.name) |
683 | self.assertDisplaysError('~%s' % owner.name, requiredMessage) |
684 | |
685 | def test_invalid_product_name(self): |
686 | # error notification if the thing following +branch has an invalid |
687 | # product name. |
688 | - self.assertDisplaysError('_foo', u"Invalid name for product: _foo.") |
689 | + self.assertDisplaysError('_foo', "Invalid name for product: _foo.") |
690 | |
691 | def test_invalid_product_name_without_referer(self): |
692 | # error notification if the thing following +branch has an invalid |
693 | @@ -350,8 +349,7 @@ class TestCodeTraversal(TestCaseWithFactory, TraversalMixin): |
694 | layer = DatabaseFunctionalLayer |
695 | |
696 | def traverse(self, path, **kwargs): |
697 | - return super(TestCodeTraversal, self).traverse( |
698 | - path, '+code', **kwargs) |
699 | + return super().traverse(path, '+code', **kwargs) |
700 | |
701 | def test_project_bzr_branch(self): |
702 | branch = self.factory.makeAnyBranch() |
703 | @@ -603,7 +601,7 @@ class TestPersonTraversal(TestCaseWithFactory, TraversalMixin): |
704 | layer = DatabaseFunctionalLayer |
705 | |
706 | def setUp(self): |
707 | - super(TestPersonTraversal, self).setUp() |
708 | + super().setUp() |
709 | self.any_user = self.factory.makePerson() |
710 | self.admin = getUtility(IPersonSet).getByName('name16') |
711 | self.registry_expert = self.factory.makePerson() |
712 | @@ -638,7 +636,7 @@ class TestPersonTraversal(TestCaseWithFactory, TraversalMixin): |
713 | |
714 | def test_placeholder_person_visibility(self): |
715 | # Verify a placeholder user is only traversable by an admin. |
716 | - name = u'placeholder-person' |
717 | + name = 'placeholder-person' |
718 | person = getUtility(IPersonSet).createPlaceholderPerson(name, name) |
719 | login_person(self.admin) |
720 | segment = '~%s' % name |
721 | @@ -765,7 +763,7 @@ class TestProductTraversal(TestCaseWithFactory, TraversalMixin): |
722 | layer = DatabaseFunctionalLayer |
723 | |
724 | def setUp(self): |
725 | - super(TestProductTraversal, self).setUp() |
726 | + super().setUp() |
727 | self.active_public_product = self.factory.makeProduct() |
728 | self.inactive_public_product = self.factory.makeProduct() |
729 | removeSecurityProxy(self.inactive_public_product).active = False |
730 | diff --git a/lib/lp/app/browser/tests/test_launchpadform.py b/lib/lp/app/browser/tests/test_launchpadform.py |
731 | index 95190a5..cb08991 100644 |
732 | --- a/lib/lp/app/browser/tests/test_launchpadform.py |
733 | +++ b/lib/lp/app/browser/tests/test_launchpadform.py |
734 | @@ -41,11 +41,11 @@ from lp.testing.layers import ( |
735 | class TestInterface(Interface): |
736 | """Test interface for the view below.""" |
737 | |
738 | - normal = Text(title=u'normal', description=u'plain text') |
739 | + normal = Text(title='normal', description='plain text') |
740 | |
741 | structured = has_structured_doc( |
742 | - Text(title=u'structured', |
743 | - description=u'<strong>structured text</strong')) |
744 | + Text(title='structured', |
745 | + description='<strong>structured text</strong')) |
746 | |
747 | |
748 | class TestView(LaunchpadFormView): |
749 | @@ -90,9 +90,9 @@ class TestQueryTalesForHasStructuredDoc(TestCase): |
750 | class TestHelpLinksInterface(Interface): |
751 | """Test interface for the view below.""" |
752 | |
753 | - nickname = Text(title=u'nickname') |
754 | + nickname = Text(title='nickname') |
755 | |
756 | - displayname = Text(title=u'displayname') |
757 | + displayname = Text(title='displayname') |
758 | |
759 | |
760 | class TestHelpLinksView(LaunchpadFormView): |
761 | @@ -100,13 +100,13 @@ class TestHelpLinksView(LaunchpadFormView): |
762 | |
763 | schema = TestHelpLinksInterface |
764 | |
765 | - page_title = u"TestHelpLinksView" |
766 | + page_title = "TestHelpLinksView" |
767 | template = ViewPageTemplateFile( |
768 | config.root + '/lib/lp/app/templates/generic-edit.pt') |
769 | |
770 | help_links = { |
771 | - "nickname": u"http://widget.example.com/name", |
772 | - "displayname": u"http://widget.example.com/displayname", |
773 | + "nickname": "http://widget.example.com/name", |
774 | + "displayname": "http://widget.example.com/displayname", |
775 | } |
776 | |
777 | |
778 | @@ -122,10 +122,10 @@ class TestHelpLinks(TestCaseWithFactory): |
779 | view.initialize() |
780 | nickname_widget, displayname_widget = view.widgets |
781 | self.assertEqual( |
782 | - u"http://widget.example.com/name", |
783 | + "http://widget.example.com/name", |
784 | nickname_widget.help_link) |
785 | self.assertEqual( |
786 | - u"http://widget.example.com/displayname", |
787 | + "http://widget.example.com/displayname", |
788 | displayname_widget.help_link) |
789 | |
790 | def test_help_links_render(self): |
791 | @@ -140,20 +140,20 @@ class TestHelpLinks(TestCaseWithFactory): |
792 | [nickname_help_link] = root.cssselect( |
793 | "label[for$=nickname] ~ a[target=help]") |
794 | self.assertEqual( |
795 | - u"http://widget.example.com/name", |
796 | + "http://widget.example.com/name", |
797 | nickname_help_link.get("href")) |
798 | [displayname_help_link] = root.cssselect( |
799 | "label[for$=displayname] ~ a[target=help]") |
800 | self.assertEqual( |
801 | - u"http://widget.example.com/displayname", |
802 | + "http://widget.example.com/displayname", |
803 | displayname_help_link.get("href")) |
804 | |
805 | |
806 | class TestWidgetDivInterface(Interface): |
807 | """Test interface for the view below.""" |
808 | |
809 | - single_line = TextLine(title=u'single_line') |
810 | - multi_line = Text(title=u'multi_line') |
811 | + single_line = TextLine(title='single_line') |
812 | + multi_line = Text(title='multi_line') |
813 | checkbox = Choice( |
814 | vocabulary=SimpleVocabulary.fromItems( |
815 | (('yes', True), ('no', False)))) |
816 | diff --git a/lib/lp/app/browser/tests/test_launchpadroot.py b/lib/lp/app/browser/tests/test_launchpadroot.py |
817 | index 92cc935..5c3b1d7 100644 |
818 | --- a/lib/lp/app/browser/tests/test_launchpadroot.py |
819 | +++ b/lib/lp/app/browser/tests/test_launchpadroot.py |
820 | @@ -127,7 +127,7 @@ class LaunchpadRootIndexViewTestCase(TestCaseWithFactory): |
821 | layer = LaunchpadFunctionalLayer |
822 | |
823 | def setUp(self): |
824 | - super(LaunchpadRootIndexViewTestCase, self).setUp() |
825 | + super().setUp() |
826 | # Use a FakeLogger fixture to prevent Memcached warnings to be |
827 | # printed to stdout while browsing pages. |
828 | self.useFixture(FakeLogger()) |
829 | diff --git a/lib/lp/app/browser/tests/test_mixed_visibility.py b/lib/lp/app/browser/tests/test_mixed_visibility.py |
830 | index be6014a..ee7bcce 100644 |
831 | --- a/lib/lp/app/browser/tests/test_mixed_visibility.py |
832 | +++ b/lib/lp/app/browser/tests/test_mixed_visibility.py |
833 | @@ -21,7 +21,7 @@ class TestMixedVisibility(TestCaseWithFactory): |
834 | viewer = self.factory.makePerson() |
835 | with person_logged_in(viewer): |
836 | self.assertEqual( |
837 | - u'<hidden>', TeamFormatterAPI(team).displayname(None)) |
838 | + '<hidden>', TeamFormatterAPI(team).displayname(None)) |
839 | self.assertEqual(1, len(self.oopses)) |
840 | self.assertTrue( |
841 | 'MixedVisibilityError' in self.oopses[0]['tb_text']) |
842 | diff --git a/lib/lp/app/browser/tests/test_page_macro.py b/lib/lp/app/browser/tests/test_page_macro.py |
843 | index 6184afd..fb8f1fd 100644 |
844 | --- a/lib/lp/app/browser/tests/test_page_macro.py |
845 | +++ b/lib/lp/app/browser/tests/test_page_macro.py |
846 | @@ -63,7 +63,7 @@ class PageMacroDispatcherTestCase(TestPageMacroDispatcherMixin, TestCase): |
847 | layer = FunctionalLayer |
848 | |
849 | def setUp(self): |
850 | - super(PageMacroDispatcherTestCase, self).setUp() |
851 | + super().setUp() |
852 | self._setUpView() |
853 | |
854 | def test_base_template(self): |
855 | @@ -152,7 +152,7 @@ class PageMacroDispatcherInteractionTestCase(TestPageMacroDispatcherMixin, |
856 | layer = DatabaseFunctionalLayer |
857 | |
858 | def setUp(self): |
859 | - super(PageMacroDispatcherInteractionTestCase, self).setUp() |
860 | + super().setUp() |
861 | self._setUpView() |
862 | login_person(self.factory.makePerson()) |
863 | |
864 | @@ -165,7 +165,7 @@ class PageMacroDispatcherInteractionTestCase(TestPageMacroDispatcherMixin, |
865 | return FakeSecurityChecker(adaptee) |
866 | |
867 | def __init__(self, adaptee=None): |
868 | - super(FakeSecurityChecker, self).__init__(adaptee) |
869 | + super().__init__(adaptee) |
870 | |
871 | def checkUnauthenticated(self): |
872 | return has_permission |
873 | diff --git a/lib/lp/app/browser/tests/test_stringformatter.py b/lib/lp/app/browser/tests/test_stringformatter.py |
874 | index 0266453..1663f49 100644 |
875 | --- a/lib/lp/app/browser/tests/test_stringformatter.py |
876 | +++ b/lib/lp/app/browser/tests/test_stringformatter.py |
877 | @@ -315,8 +315,8 @@ class TestParseDiff(TestCase): |
878 | def test_unicode(self): |
879 | # Diffs containing Unicode work too. |
880 | self.assertEqual( |
881 | - [('text', 1, 0, 0, u'Unicode \u1010')], |
882 | - list(parse_diff(u'Unicode \u1010'))) |
883 | + [('text', 1, 0, 0, 'Unicode \u1010')], |
884 | + list(parse_diff('Unicode \u1010'))) |
885 | |
886 | def assertParses(self, expected, diff): |
887 | diff_lines = diff.splitlines() |
888 | @@ -488,10 +488,10 @@ class TestDiffFormatter(TestCase): |
889 | def test_format_unicode(self): |
890 | # Sometimes the strings contain unicode, those should work too. |
891 | self.assertEqual( |
892 | - u'<table class="diff unidiff"><tr id="diff-line-1">' |
893 | - u'<td class="line-no unselectable">1</td><td class="text">' |
894 | - u'Unicode \u1010</td></tr></table>', |
895 | - FormattersAPI(u'Unicode \u1010').format_diff()) |
896 | + '<table class="diff unidiff"><tr id="diff-line-1">' |
897 | + '<td class="line-no unselectable">1</td><td class="text">' |
898 | + 'Unicode \u1010</td></tr></table>', |
899 | + FormattersAPI('Unicode \u1010').format_diff()) |
900 | |
901 | def test_cssClasses(self): |
902 | # Different parts of the diff have different css classes. |
903 | @@ -586,14 +586,14 @@ class TestSideBySideDiffFormatter(TestCase): |
904 | def test_format_unicode(self): |
905 | # Sometimes the strings contain unicode, those should work too. |
906 | self.assertEqual( |
907 | - u'<table class="diff ssdiff"><tr id="diff-line-1">' |
908 | - u'<td class="line-no unselectable" style="display: none">1</td>' |
909 | - u'<td class="ss-line-no unselectable">0</td>' |
910 | - u'<td class="text">Unicode \u1010</td>' |
911 | - u'<td class="ss-line-no unselectable">0</td>' |
912 | - u'<td class="text">Unicode \u1010</td>' |
913 | - u'</tr></table>', |
914 | - FormattersAPI(u'Unicode \u1010').format_ssdiff()) |
915 | + '<table class="diff ssdiff"><tr id="diff-line-1">' |
916 | + '<td class="line-no unselectable" style="display: none">1</td>' |
917 | + '<td class="ss-line-no unselectable">0</td>' |
918 | + '<td class="text">Unicode \u1010</td>' |
919 | + '<td class="ss-line-no unselectable">0</td>' |
920 | + '<td class="text">Unicode \u1010</td>' |
921 | + '</tr></table>', |
922 | + FormattersAPI('Unicode \u1010').format_ssdiff()) |
923 | |
924 | def test_cssClasses(self): |
925 | # Different parts of the diff have different css classes. |
926 | @@ -743,7 +743,7 @@ class TestMarkdownDisabled(TestCase): |
927 | layer = DatabaseFunctionalLayer # Fixtures need the database for now |
928 | |
929 | def setUp(self): |
930 | - super(TestMarkdownDisabled, self).setUp() |
931 | + super().setUp() |
932 | self.useFixture(FeatureFixture({'markdown.enabled': None})) |
933 | |
934 | def test_plain_text(self): |
935 | @@ -762,7 +762,7 @@ class TestMarkdown(TestCase): |
936 | layer = DatabaseFunctionalLayer # Fixtures need the database for now |
937 | |
938 | def setUp(self): |
939 | - super(TestMarkdown, self).setUp() |
940 | + super().setUp() |
941 | self.useFixture(FeatureFixture({'markdown.enabled': 'on'})) |
942 | |
943 | def test_plain_text(self): |
944 | diff --git a/lib/lp/app/browser/tests/test_vocabulary.py b/lib/lp/app/browser/tests/test_vocabulary.py |
945 | index c7cf33d..2585a02 100644 |
946 | --- a/lib/lp/app/browser/tests/test_vocabulary.py |
947 | +++ b/lib/lp/app/browser/tests/test_vocabulary.py |
948 | @@ -487,7 +487,7 @@ class HugeVocabularyJSONViewTestCase(TestCaseWithFactory): |
949 | layer = DatabaseFunctionalLayer |
950 | |
951 | def setUp(self): |
952 | - super(HugeVocabularyJSONViewTestCase, self).setUp() |
953 | + super().setUp() |
954 | test_persons = [] |
955 | for name in range(1, 7): |
956 | test_persons.append( |
957 | diff --git a/lib/lp/app/browser/tests/test_webservice.py b/lib/lp/app/browser/tests/test_webservice.py |
958 | index 0237760..7af01a7 100644 |
959 | --- a/lib/lp/app/browser/tests/test_webservice.py |
960 | +++ b/lib/lp/app/browser/tests/test_webservice.py |
961 | @@ -33,7 +33,7 @@ class TestXHTMLRepresentations(TestCaseWithFactory): |
962 | |
963 | def test_text(self): |
964 | # Test the XHTML representation of a text field. |
965 | - text = u'\N{SNOWMAN} snowman@example.com bug 1' |
966 | + text = '\N{SNOWMAN} snowman@example.com bug 1' |
967 | # We need something that has an IPersonChoice, a project will do. |
968 | product = self.factory.makeProduct() |
969 | field = IProduct['description'] |
970 | @@ -42,7 +42,7 @@ class TestXHTMLRepresentations(TestCaseWithFactory): |
971 | (product, field, request), IFieldHTMLRenderer) |
972 | # The representation is linkified html. |
973 | self.assertEqual( |
974 | - u'<p>\N{SNOWMAN} snowman@example.com ' |
975 | + '<p>\N{SNOWMAN} snowman@example.com ' |
976 | '<a href="/bugs/1" class="bug-link">bug 1</a></p>', |
977 | renderer(text)) |
978 | |
979 | diff --git a/lib/lp/app/browser/vocabulary.py b/lib/lp/app/browser/vocabulary.py |
980 | index 4f3cde4..7cf7eb3 100644 |
981 | --- a/lib/lp/app/browser/vocabulary.py |
982 | +++ b/lib/lp/app/browser/vocabulary.py |
983 | @@ -114,7 +114,7 @@ class IPickerEntrySource(Interface): |
984 | |
985 | @adapter(Interface) |
986 | @implementer(IPickerEntrySource) |
987 | -class DefaultPickerEntrySourceAdapter(object): |
988 | +class DefaultPickerEntrySourceAdapter: |
989 | """Adapts Interface to IPickerEntrySource.""" |
990 | |
991 | def __init__(self, context): |
992 | @@ -151,9 +151,7 @@ class PersonPickerEntrySourceAdapter(DefaultPickerEntrySourceAdapter): |
993 | |
994 | def getPickerEntries(self, term_values, context_object, **kwarg): |
995 | """See `IPickerEntrySource`""" |
996 | - picker_entries = ( |
997 | - super(PersonPickerEntrySourceAdapter, self) |
998 | - .getPickerEntries(term_values, context_object)) |
999 | + picker_entries = super().getPickerEntries(term_values, context_object) |
1000 | |
1001 | affiliated_context = IHasAffiliation(context_object, None) |
1002 | if affiliated_context is not None: |
1003 | @@ -214,8 +212,7 @@ class BranchPickerEntrySourceAdapter(DefaultPickerEntrySourceAdapter): |
1004 | def getPickerEntries(self, term_values, context_object, **kwarg): |
1005 | """See `IPickerEntrySource`""" |
1006 | entries = ( |
1007 | - super(BranchPickerEntrySourceAdapter, self) |
1008 | - .getPickerEntries(term_values, context_object, **kwarg)) |
1009 | + super().getPickerEntries(term_values, context_object, **kwarg)) |
1010 | for branch, picker_entry in izip(term_values, entries): |
1011 | picker_entry.description = branch.bzr_identity |
1012 | return entries |
1013 | @@ -241,8 +238,7 @@ class TargetPickerEntrySourceAdapter(DefaultPickerEntrySourceAdapter): |
1014 | def getPickerEntries(self, term_values, context_object, **kwarg): |
1015 | """See `IPickerEntrySource`""" |
1016 | entries = ( |
1017 | - super(TargetPickerEntrySourceAdapter, self) |
1018 | - .getPickerEntries(term_values, context_object, **kwarg)) |
1019 | + super().getPickerEntries(term_values, context_object, **kwarg)) |
1020 | for target, picker_entry in izip(term_values, entries): |
1021 | picker_entry.description = self.getDescription(target) |
1022 | picker_entry.details = [] |
1023 | @@ -284,8 +280,7 @@ class SourcePackageNamePickerEntrySourceAdapter( |
1024 | def getPickerEntries(self, term_values, context_object, **kwarg): |
1025 | """See `IPickerEntrySource`""" |
1026 | entries = ( |
1027 | - super(SourcePackageNamePickerEntrySourceAdapter, self) |
1028 | - .getPickerEntries(term_values, context_object, **kwarg)) |
1029 | + super().getPickerEntries(term_values, context_object, **kwarg)) |
1030 | for sourcepackagename, picker_entry in izip(term_values, entries): |
1031 | descriptions = getSourcePackageDescriptions([sourcepackagename]) |
1032 | picker_entry.description = descriptions.get( |
1033 | @@ -313,7 +308,7 @@ class DistributionSourcePackagePickerEntrySourceAdapter( |
1034 | return description |
1035 | |
1036 | def getPickerEntries(self, term_values, context_object, **kwarg): |
1037 | - this = super(DistributionSourcePackagePickerEntrySourceAdapter, self) |
1038 | + this = super() |
1039 | entries = this.getPickerEntries(term_values, context_object, **kwarg) |
1040 | for picker_entry in entries: |
1041 | picker_entry.alt_title = None |
1042 | @@ -384,8 +379,7 @@ class ArchivePickerEntrySourceAdapter(DefaultPickerEntrySourceAdapter): |
1043 | def getPickerEntries(self, term_values, context_object, **kwarg): |
1044 | """See `IPickerEntrySource`""" |
1045 | entries = ( |
1046 | - super(ArchivePickerEntrySourceAdapter, self) |
1047 | - .getPickerEntries(term_values, context_object, **kwarg)) |
1048 | + super().getPickerEntries(term_values, context_object, **kwarg)) |
1049 | for archive, picker_entry in izip(term_values, entries): |
1050 | picker_entry.description = archive.reference |
1051 | return entries |
1052 | diff --git a/lib/lp/app/model/launchpad.py b/lib/lp/app/model/launchpad.py |
1053 | index 22156c3..b03359d 100644 |
1054 | --- a/lib/lp/app/model/launchpad.py |
1055 | +++ b/lib/lp/app/model/launchpad.py |
1056 | @@ -37,7 +37,7 @@ class ExceptionPrivacy(Privacy): |
1057 | private = True |
1058 | else: |
1059 | private = False |
1060 | - super(ExceptionPrivacy, self).__init__(error, private) |
1061 | + super().__init__(error, private) |
1062 | |
1063 | |
1064 | class InformationTypeMixin: |
1065 | diff --git a/lib/lp/app/security.py b/lib/lp/app/security.py |
1066 | index e3fb8b1..2500a80 100644 |
1067 | --- a/lib/lp/app/security.py |
1068 | +++ b/lib/lp/app/security.py |
1069 | @@ -129,7 +129,7 @@ class non_boolean_izip(izip): |
1070 | class DelegatedAuthorization(AuthorizationBase): |
1071 | |
1072 | def __init__(self, obj, forwarded_object=None, permission=None): |
1073 | - super(DelegatedAuthorization, self).__init__(obj) |
1074 | + super().__init__(obj) |
1075 | self.forwarded_object = forwarded_object |
1076 | if permission is not None: |
1077 | self.permission = permission |
1078 | diff --git a/lib/lp/app/services.py b/lib/lp/app/services.py |
1079 | index 154d44f..f18ccad 100644 |
1080 | --- a/lib/lp/app/services.py |
1081 | +++ b/lib/lp/app/services.py |
1082 | @@ -26,7 +26,7 @@ class ServiceFactory(Navigation): |
1083 | """ |
1084 | |
1085 | def __init__(self): |
1086 | - super(ServiceFactory, self).__init__(None) |
1087 | + super().__init__(None) |
1088 | |
1089 | def traverse(self, name): |
1090 | return self.getService(name) |
1091 | diff --git a/lib/lp/app/tests/test_security.py b/lib/lp/app/tests/test_security.py |
1092 | index febb5b9..cd8ecce 100644 |
1093 | --- a/lib/lp/app/tests/test_security.py |
1094 | +++ b/lib/lp/app/tests/test_security.py |
1095 | @@ -59,7 +59,7 @@ def registerFakeSecurityAdapter(interface, permission, adapter=None): |
1096 | class FakeSecurityAdapter(AuthorizationBase): |
1097 | |
1098 | def __init__(self, adaptee=None): |
1099 | - super(FakeSecurityAdapter, self).__init__(adaptee) |
1100 | + super().__init__(adaptee) |
1101 | self.checkAuthenticated = FakeMethod() |
1102 | self.checkUnauthenticated = FakeMethod() |
1103 | |
1104 | diff --git a/lib/lp/app/tests/test_tales.py b/lib/lp/app/tests/test_tales.py |
1105 | index ffd5f91..d238e2b 100644 |
1106 | --- a/lib/lp/app/tests/test_tales.py |
1107 | +++ b/lib/lp/app/tests/test_tales.py |
1108 | @@ -162,7 +162,7 @@ class TestTeamFormatterAPI(TestCaseWithFactory): |
1109 | layer = LaunchpadFunctionalLayer |
1110 | |
1111 | def setUp(self): |
1112 | - super(TestTeamFormatterAPI, self).setUp() |
1113 | + super().setUp() |
1114 | icon = self.factory.makeLibraryFileAlias( |
1115 | filename='smurf.png', content_type='image/png') |
1116 | self.team = self.factory.makeTeam( |
1117 | @@ -227,7 +227,7 @@ class TestTeamFormatterAPI(TestCaseWithFactory): |
1118 | |
1119 | def test_can_view_link(self): |
1120 | self._test_can_view_attribute( |
1121 | - 'link', u'<span class="sprite team"><hidden></span>') |
1122 | + 'link', '<span class="sprite team"><hidden></span>') |
1123 | |
1124 | def test_can_view_api_url(self): |
1125 | self._test_can_view_attribute('api_url') |
1126 | @@ -396,7 +396,7 @@ class TestIRCNicknameFormatterAPI(TestCaseWithFactory): |
1127 | expected_html = test_tales( |
1128 | 'nick/fmt:formatted_displayname', nick=ircID) |
1129 | self.assertEqual( |
1130 | - u'<strong>fred</strong>\n' |
1131 | + '<strong>fred</strong>\n' |
1132 | '<span class="lesser"> on </span>\n' |
1133 | '<strong><b>irc.canonical.com</b></strong>\n', |
1134 | expected_html) |
1135 | diff --git a/lib/lp/app/utilities/celebrities.py b/lib/lp/app/utilities/celebrities.py |
1136 | index 99a7f70..b26d830 100644 |
1137 | --- a/lib/lp/app/utilities/celebrities.py |
1138 | +++ b/lib/lp/app/utilities/celebrities.py |
1139 | @@ -104,7 +104,7 @@ class PersonCelebrityDescriptor(CelebrityDescriptor): |
1140 | |
1141 | def __init__(self, name): |
1142 | PersonCelebrityDescriptor.names.add(name) |
1143 | - super(PersonCelebrityDescriptor, self).__init__(IPersonSet, name) |
1144 | + super().__init__(IPersonSet, name) |
1145 | |
1146 | |
1147 | class LanguageCelebrityDescriptor(CelebrityDescriptor): |
1148 | diff --git a/lib/lp/app/validators/attachment.py b/lib/lp/app/validators/attachment.py |
1149 | index 404790f..566ab85 100644 |
1150 | --- a/lib/lp/app/validators/attachment.py |
1151 | +++ b/lib/lp/app/validators/attachment.py |
1152 | @@ -17,9 +17,9 @@ def attachment_size_constraint(value): |
1153 | size = len(value) |
1154 | max_size = config.launchpad.max_attachment_size |
1155 | if size == 0: |
1156 | - raise LaunchpadValidationError(u'Cannot upload empty file.') |
1157 | + raise LaunchpadValidationError('Cannot upload empty file.') |
1158 | elif max_size > 0 and size > max_size: |
1159 | raise LaunchpadValidationError( |
1160 | - u'Cannot upload files larger than %i bytes' % max_size) |
1161 | + 'Cannot upload files larger than %i bytes' % max_size) |
1162 | else: |
1163 | return True |
1164 | diff --git a/lib/lp/app/vocabularies.py b/lib/lp/app/vocabularies.py |
1165 | index a6e7a87..33eea4a 100644 |
1166 | --- a/lib/lp/app/vocabularies.py |
1167 | +++ b/lib/lp/app/vocabularies.py |
1168 | @@ -44,4 +44,4 @@ class InformationTypeVocabulary(SimpleVocabulary): |
1169 | term.name = type.name |
1170 | term.description = type.description |
1171 | terms.append(term) |
1172 | - super(InformationTypeVocabulary, self).__init__(terms) |
1173 | + super().__init__(terms) |
1174 | diff --git a/lib/lp/app/webservice/tests/test_marshallers.py b/lib/lp/app/webservice/tests/test_marshallers.py |
1175 | index 1a6ce21..96b305f 100644 |
1176 | --- a/lib/lp/app/webservice/tests/test_marshallers.py |
1177 | +++ b/lib/lp/app/webservice/tests/test_marshallers.py |
1178 | @@ -48,15 +48,15 @@ class TestTextFieldMarshaller(TestCaseWithFactory): |
1179 | def test_unmarshall_obfuscated(self): |
1180 | # Data is obfuscated if the user is anonynous. |
1181 | marshaller = TextFieldMarshaller(None, WebServiceTestRequest()) |
1182 | - result = marshaller.unmarshall(None, u"foo@example.com") |
1183 | - self.assertEqual(u"<email address hidden>", result) |
1184 | + result = marshaller.unmarshall(None, "foo@example.com") |
1185 | + self.assertEqual("<email address hidden>", result) |
1186 | |
1187 | def test_unmarshall_not_obfuscated(self): |
1188 | # Data is not obfuscated if the user is authenticated. |
1189 | marshaller = TextFieldMarshaller(None, WebServiceTestRequest()) |
1190 | with person_logged_in(self.factory.makePerson()): |
1191 | - result = marshaller.unmarshall(None, u"foo@example.com") |
1192 | - self.assertEqual(u"foo@example.com", result) |
1193 | + result = marshaller.unmarshall(None, "foo@example.com") |
1194 | + self.assertEqual("foo@example.com", result) |
1195 | |
1196 | |
1197 | class TestWebServiceObfuscation(TestCaseWithFactory): |
1198 | diff --git a/lib/lp/app/widgets/date.py b/lib/lp/app/widgets/date.py |
1199 | index 7d9a780..0f9c52d 100644 |
1200 | --- a/lib/lp/app/widgets/date.py |
1201 | +++ b/lib/lp/app/widgets/date.py |
1202 | @@ -128,7 +128,7 @@ class DateTimeWidget(TextWidget): |
1203 | __call__ = ViewPageTemplateFile('templates/datetime.pt') |
1204 | |
1205 | def __init__(self, context, request): |
1206 | - super(DateTimeWidget, self).__init__(context, request) |
1207 | + super().__init__(context, request) |
1208 | launchbag = getUtility(ILaunchBag) |
1209 | self.system_time_zone = launchbag.time_zone |
1210 | |
1211 | @@ -313,7 +313,7 @@ class DateTimeWidget(TextWidget): |
1212 | |
1213 | def getInputValue(self): |
1214 | """Return the date, if it is in the allowed date range.""" |
1215 | - value = super(DateTimeWidget, self).getInputValue() |
1216 | + value = super().getInputValue() |
1217 | if value is None: |
1218 | return None |
1219 | # Establish if the value is within the date range. |
1220 | @@ -613,6 +613,6 @@ class DatetimeDisplayWidget(DisplayWidget): |
1221 | else: |
1222 | value = self.context.default |
1223 | if value == self.context.missing_value: |
1224 | - return u"" |
1225 | + return "" |
1226 | value = value.astimezone(time_zone) |
1227 | return html_escape(value.strftime("%Y-%m-%d %H:%M:%S %Z")) |
1228 | diff --git a/lib/lp/app/widgets/exception.py b/lib/lp/app/widgets/exception.py |
1229 | index a7c68a7..e91f643 100644 |
1230 | --- a/lib/lp/app/widgets/exception.py |
1231 | +++ b/lib/lp/app/widgets/exception.py |
1232 | @@ -36,7 +36,7 @@ class WidgetInputError(_WidgetInputError): |
1233 | |
1234 | |
1235 | @implementer(IWidgetInputErrorView) |
1236 | -class WidgetInputErrorView(object): |
1237 | +class WidgetInputErrorView: |
1238 | """Rendering of IWidgetInputError""" |
1239 | |
1240 | def __init__(self, context, request): |
1241 | diff --git a/lib/lp/app/widgets/itemswidgets.py b/lib/lp/app/widgets/itemswidgets.py |
1242 | index 571f65f..c3142ba 100644 |
1243 | --- a/lib/lp/app/widgets/itemswidgets.py |
1244 | +++ b/lib/lp/app/widgets/itemswidgets.py |
1245 | @@ -38,7 +38,7 @@ class LaunchpadDropdownWidget(DropdownWidget): |
1246 | class PlainMultiCheckBoxWidget(MultiCheckBoxWidget): |
1247 | """MultiCheckBoxWidget that copes with CustomWidgetFactory.""" |
1248 | |
1249 | - _joinButtonToMessageTemplate = u'%s %s ' |
1250 | + _joinButtonToMessageTemplate = '%s %s ' |
1251 | |
1252 | def __init__(self, field, vocabulary, request): |
1253 | # XXX flacoste 2006-07-23 Workaround Zope3 bug #545: |
1254 | @@ -70,7 +70,7 @@ class PlainMultiCheckBoxWidget(MultiCheckBoxWidget): |
1255 | text = html_escape(text) |
1256 | id = '%s.%s' % (name, index) |
1257 | element = renderElement( |
1258 | - u'input', value=value, name=name, id=id, |
1259 | + 'input', value=value, name=name, id=id, |
1260 | cssClass=cssClass, type='checkbox', **kw) |
1261 | return self._joinButtonToMessageTemplate % (element, text) |
1262 | |
1263 | @@ -81,7 +81,7 @@ class LabeledMultiCheckBoxWidget(PlainMultiCheckBoxWidget): |
1264 | """ |
1265 | |
1266 | _joinButtonToMessageTemplate = ( |
1267 | - u'<label for="%s" style="font-weight: normal">%s %s</label> ') |
1268 | + '<label for="%s" style="font-weight: normal">%s %s</label> ') |
1269 | |
1270 | def _renderItem(self, index, text, value, name, cssClass, checked=False): |
1271 | """Render a checkbox and text in a label with a style attribute.""" |
1272 | @@ -93,7 +93,7 @@ class LabeledMultiCheckBoxWidget(PlainMultiCheckBoxWidget): |
1273 | value = html_escape(value) |
1274 | text = html_escape(text) |
1275 | id = '%s.%s' % (name, index) |
1276 | - elem = renderElement(u'input', |
1277 | + elem = renderElement('input', |
1278 | value=value, |
1279 | name=name, |
1280 | id=id, |
1281 | @@ -119,7 +119,7 @@ class LaunchpadRadioWidget(RadioWidget): |
1282 | value = html_escape(value) |
1283 | text = html_escape(text) |
1284 | id = '%s.%s' % (name, index) |
1285 | - elem = renderElement(u'input', |
1286 | + elem = renderElement('input', |
1287 | value=value, |
1288 | name=name, |
1289 | id=id, |
1290 | @@ -129,7 +129,7 @@ class LaunchpadRadioWidget(RadioWidget): |
1291 | if '<label' in text: |
1292 | return '%s %s' % (elem, text) |
1293 | else: |
1294 | - return renderElement(u'label', |
1295 | + return renderElement('label', |
1296 | contents='%s %s' % (elem, text), |
1297 | **{'style': 'font-weight: normal'}) |
1298 | |
1299 | @@ -145,27 +145,26 @@ class LaunchpadRadioWidgetWithDescription(LaunchpadRadioWidget): |
1300 | """ |
1301 | |
1302 | _labelWithDescriptionTemplate = ( |
1303 | - u'''<tr> |
1304 | - <td rowspan="2">%s</td> |
1305 | - <td><label for="%s">%s</label></td> |
1306 | - </tr> |
1307 | - <tr> |
1308 | - <td class="formHelp">%s</td> |
1309 | - </tr> |
1310 | - ''') |
1311 | + '''<tr> |
1312 | + <td rowspan="2">%s</td> |
1313 | + <td><label for="%s">%s</label></td> |
1314 | + </tr> |
1315 | + <tr> |
1316 | + <td class="formHelp">%s</td> |
1317 | + </tr> |
1318 | + ''') |
1319 | _labelWithoutDescriptionTemplate = ( |
1320 | - u'''<tr> |
1321 | - <td>%s</td> |
1322 | - <td><label for="%s">%s</label></td> |
1323 | - </tr> |
1324 | - ''') |
1325 | + '''<tr> |
1326 | + <td>%s</td> |
1327 | + <td><label for="%s">%s</label></td> |
1328 | + </tr> |
1329 | + ''') |
1330 | |
1331 | def __init__(self, field, vocabulary, request): |
1332 | """Initialize the widget.""" |
1333 | assert IEnumeratedType.providedBy(vocabulary), ( |
1334 | 'The vocabulary must implement IEnumeratedType') |
1335 | - super(LaunchpadRadioWidgetWithDescription, self).__init__( |
1336 | - field, vocabulary, request) |
1337 | + super().__init__(field, vocabulary, request) |
1338 | self.extra_hint = None |
1339 | self.extra_hint_class = None |
1340 | |
1341 | @@ -187,7 +186,7 @@ class LaunchpadRadioWidgetWithDescription(LaunchpadRadioWidget): |
1342 | """Render an item of the list.""" |
1343 | text = html_escape(text) |
1344 | id = '%s.%s' % (name, index) |
1345 | - elem = renderElement(u'input', |
1346 | + elem = renderElement('input', |
1347 | value=value, |
1348 | name=name, |
1349 | id=id, |
1350 | @@ -199,7 +198,7 @@ class LaunchpadRadioWidgetWithDescription(LaunchpadRadioWidget): |
1351 | """Render a selected item of the list.""" |
1352 | text = html_escape(text) |
1353 | id = '%s.%s' % (name, index) |
1354 | - elem = renderElement(u'input', |
1355 | + elem = renderElement('input', |
1356 | value=value, |
1357 | name=name, |
1358 | id=id, |
1359 | @@ -245,8 +244,7 @@ class LaunchpadBooleanRadioWidget(LaunchpadRadioWidget): |
1360 | """Initialize the widget.""" |
1361 | vocabulary = SimpleVocabulary.fromItems( |
1362 | ((self.TRUE, True), (self.FALSE, False))) |
1363 | - super(LaunchpadBooleanRadioWidget, self).__init__( |
1364 | - field, vocabulary, request) |
1365 | + super().__init__(field, vocabulary, request) |
1366 | # Suppress the missing value behaviour; this is a boolean field. |
1367 | self.required = True |
1368 | self._displayItemForMissingValue = False |
1369 | @@ -261,7 +259,7 @@ class LaunchpadBooleanRadioWidget(LaunchpadRadioWidget): |
1370 | else: |
1371 | # value == self.FALSE. |
1372 | text = self.false_label |
1373 | - return super(LaunchpadBooleanRadioWidget, self)._renderItem( |
1374 | + return super()._renderItem( |
1375 | index, text, value, name, cssClass, checked=checked) |
1376 | |
1377 | |
1378 | diff --git a/lib/lp/app/widgets/launchpadtarget.py b/lib/lp/app/widgets/launchpadtarget.py |
1379 | index 57d684e..3a9b805 100644 |
1380 | --- a/lib/lp/app/widgets/launchpadtarget.py |
1381 | +++ b/lib/lp/app/widgets/launchpadtarget.py |
1382 | @@ -66,14 +66,14 @@ class LaunchpadTargetWidget(BrowserWidget, InputWidget): |
1383 | return |
1384 | fields = [ |
1385 | Choice( |
1386 | - __name__='product', title=u'Project', |
1387 | + __name__='product', title='Project', |
1388 | required=True, vocabulary=self.getProductVocabulary()), |
1389 | Choice( |
1390 | - __name__='distribution', title=u"Distribution", |
1391 | + __name__='distribution', title="Distribution", |
1392 | required=True, vocabulary=self.getDistributionVocabulary(), |
1393 | default=getUtility(ILaunchpadCelebrities).ubuntu), |
1394 | Choice( |
1395 | - __name__='package', title=u"Package", |
1396 | + __name__='package', title="Package", |
1397 | required=False, vocabulary=self.getPackageVocabularyName()), |
1398 | ] |
1399 | self.distribution_widget = CustomWidgetFactory( |
1400 | diff --git a/lib/lp/app/widgets/owner.py b/lib/lp/app/widgets/owner.py |
1401 | index e9fccae..477f98c 100644 |
1402 | --- a/lib/lp/app/widgets/owner.py |
1403 | +++ b/lib/lp/app/widgets/owner.py |
1404 | @@ -15,7 +15,7 @@ from lp.services.webapp.interfaces import ILaunchBag |
1405 | |
1406 | |
1407 | @implementer(IInputWidget, IBrowserWidget) |
1408 | -class RequestWidget(object): |
1409 | +class RequestWidget: |
1410 | '''A widget that sets itself to a value calculated from request |
1411 | |
1412 | This is a bit of a hack, but necessary. If we are using the Zope |
1413 | diff --git a/lib/lp/app/widgets/popup.py b/lib/lp/app/widgets/popup.py |
1414 | index d5e4ec5..34264ae 100644 |
1415 | --- a/lib/lp/app/widgets/popup.py |
1416 | +++ b/lib/lp/app/widgets/popup.py |
1417 | @@ -15,7 +15,6 @@ __all__ = [ |
1418 | |
1419 | from lazr.restful.utils import safe_hasattr |
1420 | import simplejson |
1421 | -import six |
1422 | from zope.browserpage import ViewPageTemplateFile |
1423 | from zope.component import getUtility |
1424 | from zope.formlib.interfaces import ConversionError |
1425 | @@ -77,14 +76,14 @@ class VocabularyPickerWidget(SingleDataHelper, ItemsWidgetBase): |
1426 | user currently has entered in the form. |
1427 | """ |
1428 | # Pull form value using the parent class to avoid loop |
1429 | - formValue = super(VocabularyPickerWidget, self)._getFormInput() |
1430 | + formValue = super()._getFormInput() |
1431 | if not formValue: |
1432 | return [] |
1433 | |
1434 | vocab = self.vocabulary |
1435 | # Special case - if the entered value is valid, it is an object |
1436 | # rather than a string (I think this is a bug somewhere) |
1437 | - if not isinstance(formValue, six.string_types): |
1438 | + if not isinstance(formValue, str): |
1439 | return [vocab.getTerm(formValue)] |
1440 | |
1441 | search_results = vocab.searchForTerms(formValue) |
1442 | @@ -101,7 +100,7 @@ class VocabularyPickerWidget(SingleDataHelper, ItemsWidgetBase): |
1443 | val = self._getFormValue() |
1444 | |
1445 | # We have a valid object - return the corresponding token |
1446 | - if not isinstance(val, six.string_types): |
1447 | + if not isinstance(val, str): |
1448 | return self.vocabulary.getTerm(val).token |
1449 | |
1450 | # Just return the existing invalid token |
1451 | @@ -323,8 +322,7 @@ class SourcePackageNameWidgetBase(DistributionSourcePackagePickerWidget): |
1452 | distribution_id = '' |
1453 | |
1454 | def __init__(self, field, vocabulary, request): |
1455 | - super(SourcePackageNameWidgetBase, self).__init__( |
1456 | - field, vocabulary, request) |
1457 | + super().__init__(field, vocabulary, request) |
1458 | self.cached_values = {} |
1459 | if bool(getFeatureFlag('disclosure.dsp_picker.enabled')): |
1460 | # The distribution may change later when we process form input, |
1461 | diff --git a/lib/lp/app/widgets/product.py b/lib/lp/app/widgets/product.py |
1462 | index 86e1d91..1b7ca66 100644 |
1463 | --- a/lib/lp/app/widgets/product.py |
1464 | +++ b/lib/lp/app/widgets/product.py |
1465 | @@ -57,7 +57,7 @@ from lp.services.webapp.vhosts import allvhosts |
1466 | class ProductBugTrackerWidget(LaunchpadRadioWidget): |
1467 | """Widget for selecting a product bug tracker.""" |
1468 | |
1469 | - _joinButtonToMessageTemplate = u'%s %s' |
1470 | + _joinButtonToMessageTemplate = '%s %s' |
1471 | template = ViewPageTemplateFile('templates/product-bug-tracker.pt') |
1472 | |
1473 | def __init__(self, field, vocabulary, request): |
1474 | @@ -101,7 +101,7 @@ class ProductBugTrackerWidget(LaunchpadRadioWidget): |
1475 | if checked: |
1476 | kw['checked'] = 'checked' |
1477 | id = '%s.%s' % (name, index) |
1478 | - elem = renderElement(u'input', |
1479 | + elem = renderElement('input', |
1480 | value=value, |
1481 | name=name, |
1482 | id=id, |
1483 | @@ -140,13 +140,12 @@ class ProductBugTrackerWidget(LaunchpadRadioWidget): |
1484 | def _renderLabel(self, text, index): |
1485 | """Render a label for the option with the specified index.""" |
1486 | option_id = '%s.%s' % (self.name, index) |
1487 | - return u'<label for="%s" style="font-weight: normal">%s</label>' % ( |
1488 | + return '<label for="%s" style="font-weight: normal">%s</label>' % ( |
1489 | option_id, text) |
1490 | |
1491 | def error(self): |
1492 | """Concatenate errors from this widget and sub-widgets.""" |
1493 | - errors = [super(ProductBugTrackerWidget, self).error(), |
1494 | - self.upstream_email_address_widget.error()] |
1495 | + errors = [super().error(), self.upstream_email_address_widget.error()] |
1496 | return '; '.join(err for err in errors if len(err) > 0) |
1497 | |
1498 | def renderItems(self, value): |
1499 | @@ -309,7 +308,7 @@ class LicenseWidget(CheckBoxMatrixWidget): |
1500 | items_by_category = None |
1501 | |
1502 | def __init__(self, field, vocabulary, request): |
1503 | - super(LicenseWidget, self).__init__(field, vocabulary, request) |
1504 | + super().__init__(field, vocabulary, request) |
1505 | # We want to put the license_info widget inside the licences widget's |
1506 | # HTML, for better alignment and JavaScript dynamism. This is |
1507 | # accomplished by ghosting the form's license_info widget (see |
1508 | @@ -344,7 +343,7 @@ class LicenseWidget(CheckBoxMatrixWidget): |
1509 | # This will return just the DBItem's text. We want to wrap that text |
1510 | # in the URL to the licence, which is stored in the DBItem's |
1511 | # description. |
1512 | - value = super(LicenseWidget, self).textForValue(term) |
1513 | + value = super().textForValue(term) |
1514 | if term.value.url is None: |
1515 | return value |
1516 | else: |
1517 | @@ -355,14 +354,13 @@ class LicenseWidget(CheckBoxMatrixWidget): |
1518 | |
1519 | def renderItem(self, index, text, value, name, cssClass): |
1520 | """See `ItemsEditWidgetBase`.""" |
1521 | - rendered = super(LicenseWidget, self).renderItem( |
1522 | - index, text, value, name, cssClass) |
1523 | + rendered = super().renderItem(index, text, value, name, cssClass) |
1524 | self._categorize(value, rendered) |
1525 | return rendered |
1526 | |
1527 | def renderSelectedItem(self, index, text, value, name, cssClass): |
1528 | """See `ItemsEditWidgetBase`.""" |
1529 | - rendered = super(LicenseWidget, self).renderSelectedItem( |
1530 | + rendered = super().renderSelectedItem( |
1531 | index, text, value, name, cssClass) |
1532 | category = self._categorize(value, rendered) |
1533 | # Increment the category counter. This is used by the template to |
1534 | @@ -390,7 +388,7 @@ class LicenseWidget(CheckBoxMatrixWidget): |
1535 | # individual checkbox items. We don't actually care about the return |
1536 | # value though since we'll be building up our checkbox tables |
1537 | # manually. |
1538 | - super(LicenseWidget, self).__call__() |
1539 | + super().__call__() |
1540 | self.recommended = self._renderTable('recommended', 3) |
1541 | self.more = self._renderTable('more', 3) |
1542 | self.deprecated = self._renderTable('deprecated') |
1543 | diff --git a/lib/lp/app/widgets/project.py b/lib/lp/app/widgets/project.py |
1544 | index 4e5b796..151b15c 100644 |
1545 | --- a/lib/lp/app/widgets/project.py |
1546 | +++ b/lib/lp/app/widgets/project.py |
1547 | @@ -33,7 +33,7 @@ class ProjectScopeWidget(BrowserWidget, InputWidget): |
1548 | _error = None |
1549 | |
1550 | def __init__(self, field, vocabulary, request): |
1551 | - super(ProjectScopeWidget, self).__init__(field, request) |
1552 | + super().__init__(field, request) |
1553 | |
1554 | # We copy the title, description and vocabulary from the main |
1555 | # field since it determines the valid target types. |
1556 | @@ -143,4 +143,4 @@ class ProjectScopeWidget(BrowserWidget, InputWidget): |
1557 | if self._error: |
1558 | return self._error.doc() |
1559 | else: |
1560 | - return u"" |
1561 | + return "" |
1562 | diff --git a/lib/lp/app/widgets/suggestion.py b/lib/lp/app/widgets/suggestion.py |
1563 | index 6ce8e46..294489e 100644 |
1564 | --- a/lib/lp/app/widgets/suggestion.py |
1565 | +++ b/lib/lp/app/widgets/suggestion.py |
1566 | @@ -141,7 +141,7 @@ class SuggestionWidget(LaunchpadRadioWidget): |
1567 | def _renderLabel(self, text, index): |
1568 | """Render a label for the option with the specified index.""" |
1569 | label = structured( |
1570 | - u'<label for="%s" style="font-weight: normal">%s</label>', |
1571 | + '<label for="%s" style="font-weight: normal">%s</label>', |
1572 | self._optionId(index), text) |
1573 | return label |
1574 | |
1575 | @@ -183,7 +183,7 @@ class SuggestionWidget(LaunchpadRadioWidget): |
1576 | other_selection_onclick = ( |
1577 | "this.form['%s'].focus()" % self.other_selection_widget.name) |
1578 | |
1579 | - elem = renderElement(u'input', |
1580 | + elem = renderElement('input', |
1581 | value="other", |
1582 | name=self.name, |
1583 | id='%s.%s' % (self.name, index), |
1584 | @@ -264,13 +264,13 @@ class TargetBranchWidget(SuggestionWidget): |
1585 | # radio buttons that is not a hyperlink in order to select the radio |
1586 | # button. It was decided not to have the entire text as a link, but |
1587 | # instead to have a separate link to the branch details. |
1588 | - text = u'%s (<a href="%s">branch details</a>)' |
1589 | + text = '%s (<a href="%s">branch details</a>)' |
1590 | # If the branch is the development focus, say so. |
1591 | if branch == self.context.context.target.default_merge_target: |
1592 | - text += u"– <em>development focus</em>" |
1593 | + text += "– <em>development focus</em>" |
1594 | label = ( |
1595 | - u'<label for="%s" style="font-weight: normal">' + text + |
1596 | - u'</label>') |
1597 | + '<label for="%s" style="font-weight: normal">' + text + |
1598 | + '</label>') |
1599 | return structured( |
1600 | label, self._optionId(index), branch.displayname, |
1601 | canonical_url(branch)) |
1602 | @@ -345,17 +345,17 @@ class TargetGitRepositoryWidget(SuggestionWidget): |
1603 | # radio buttons that is not a hyperlink in order to select the radio |
1604 | # button. It was decided not to have the entire text as a link, but |
1605 | # instead to have a separate link to the repository details. |
1606 | - text = u'%s (<a href="%s">repository details</a>)' |
1607 | + text = '%s (<a href="%s">repository details</a>)' |
1608 | # If the repository is the default for the target, say so. |
1609 | if not IPerson.providedBy(repository.target): |
1610 | repository_set = getUtility(IGitRepositorySet) |
1611 | default_target = repository_set.getDefaultRepository( |
1612 | repository.target) |
1613 | if repository == default_target: |
1614 | - text += u"– <em>default repository</em>" |
1615 | + text += "– <em>default repository</em>" |
1616 | label = ( |
1617 | - u'<label for="%s" style="font-weight: normal">' + text + |
1618 | - u'</label>') |
1619 | + '<label for="%s" style="font-weight: normal">' + text + |
1620 | + '</label>') |
1621 | return structured( |
1622 | label, self._optionId(index), repository.display_name, |
1623 | canonical_url(repository)) |
1624 | diff --git a/lib/lp/app/widgets/tests/test_datetime.py b/lib/lp/app/widgets/tests/test_datetime.py |
1625 | index fb1f8df..c748e93 100644 |
1626 | --- a/lib/lp/app/widgets/tests/test_datetime.py |
1627 | +++ b/lib/lp/app/widgets/tests/test_datetime.py |
1628 | @@ -17,8 +17,8 @@ class TestDateTimeWidget(TestCase): |
1629 | layer = DatabaseFunctionalLayer |
1630 | |
1631 | def setUp(self): |
1632 | - super(TestDateTimeWidget, self).setUp() |
1633 | - field = Field(__name__='foo', title=u'Foo') |
1634 | + super().setUp() |
1635 | + field = Field(__name__='foo', title='Foo') |
1636 | request = LaunchpadTestRequest() |
1637 | self.widget = DateTimeWidget(field, request) |
1638 | |
1639 | diff --git a/lib/lp/app/widgets/tests/test_itemswidgets.py b/lib/lp/app/widgets/tests/test_itemswidgets.py |
1640 | index 51b31e2..903611b 100644 |
1641 | --- a/lib/lp/app/widgets/tests/test_itemswidgets.py |
1642 | +++ b/lib/lp/app/widgets/tests/test_itemswidgets.py |
1643 | @@ -49,7 +49,7 @@ class ItemWidgetTestCase(TestCaseWithFactory): |
1644 | UNSAFE_TERM = SimpleTerm('object-2', 'token-2', '<unsafe> title') |
1645 | |
1646 | def setUp(self): |
1647 | - super(ItemWidgetTestCase, self).setUp() |
1648 | + super().setUp() |
1649 | self.request = LaunchpadTestRequest() |
1650 | self.vocabulary = SimpleVocabulary([self.SAFE_TERM, self.UNSAFE_TERM]) |
1651 | field = Choice(__name__='test_field', vocabulary=self.vocabulary) |
1652 | @@ -186,7 +186,7 @@ class TestLaunchpadRadioWidgetWithDescription(TestCaseWithFactory): |
1653 | UNSAFE_TERM = Item('item-<2>', description='<unsafe> title') |
1654 | |
1655 | def setUp(self): |
1656 | - super(TestLaunchpadRadioWidgetWithDescription, self).setUp() |
1657 | + super().setUp() |
1658 | self.request = LaunchpadTestRequest() |
1659 | field = Choice(__name__='test_field', vocabulary=self.TestEnum) |
1660 | self.field = field.bind(object()) |
1661 | diff --git a/lib/lp/app/widgets/tests/test_launchpadtarget.py b/lib/lp/app/widgets/tests/test_launchpadtarget.py |
1662 | index 5deb272..e94e145 100644 |
1663 | --- a/lib/lp/app/widgets/tests/test_launchpadtarget.py |
1664 | +++ b/lib/lp/app/widgets/tests/test_launchpadtarget.py |
1665 | @@ -59,15 +59,14 @@ class LaunchpadTargetWidgetTestCase(TestCaseWithFactory): |
1666 | } |
1667 | |
1668 | def setUp(self): |
1669 | - super(LaunchpadTargetWidgetTestCase, self).setUp() |
1670 | + super().setUp() |
1671 | self.distribution = self.factory.makeDistribution(name='fnord') |
1672 | distroseries = self.factory.makeDistroSeries( |
1673 | distribution=self.distribution) |
1674 | self.package = self.factory.makeDSPCache( |
1675 | distroseries=distroseries, sourcepackagename='snarf') |
1676 | self.project = self.factory.makeProduct('pting') |
1677 | - field = Reference( |
1678 | - __name__='target', schema=Interface, title=u'target') |
1679 | + field = Reference(__name__='target', schema=Interface, title='target') |
1680 | field = field.bind(Thing()) |
1681 | request = LaunchpadTestRequest() |
1682 | self.widget = LaunchpadTargetWidget(field, request) |
1683 | @@ -129,7 +128,7 @@ class LaunchpadTargetWidgetTestCase(TestCaseWithFactory): |
1684 | def test_setUpSubWidgets_dsp_picker_feature_flag(self): |
1685 | # The DistributionSourcePackageVocabulary is used when the |
1686 | # disclosure.dsp_picker.enabled is true. |
1687 | - with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}): |
1688 | + with FeatureFixture({"disclosure.dsp_picker.enabled": "on"}): |
1689 | self.widget.setUpSubWidgets() |
1690 | self.assertIsInstance( |
1691 | self.widget.package_widget.context.vocabulary, |
1692 | @@ -200,7 +199,7 @@ class LaunchpadTargetWidgetTestCase(TestCaseWithFactory): |
1693 | # The field value is the package when the package radio button |
1694 | # is selected and the package sub field has valid input. |
1695 | self.widget.request = LaunchpadTestRequest(form=self.form) |
1696 | - with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}): |
1697 | + with FeatureFixture({"disclosure.dsp_picker.enabled": "on"}): |
1698 | self.widget.setUpSubWidgets() |
1699 | self.assertEqual(self.package, self.widget.getInputValue()) |
1700 | |
1701 | diff --git a/lib/lp/app/widgets/tests/test_popup.py b/lib/lp/app/widgets/tests/test_popup.py |
1702 | index 5627eaa..3ea8bb0 100644 |
1703 | --- a/lib/lp/app/widgets/tests/test_popup.py |
1704 | +++ b/lib/lp/app/widgets/tests/test_popup.py |
1705 | @@ -27,7 +27,7 @@ class TestMetaClass(InterfaceClass): |
1706 | "test_filtered.item": Choice(vocabulary='DistributionOrProduct'), |
1707 | "test_target": Choice(vocabulary='DistributionSourcePackage'), |
1708 | } |
1709 | - super(TestMetaClass, self).__init__( |
1710 | + super().__init__( |
1711 | name, bases=bases, attrs=attrs, __doc__=__doc__, |
1712 | __module__=__module__) |
1713 | |
1714 | @@ -42,7 +42,7 @@ class TestVocabularyPickerWidget(TestCaseWithFactory): |
1715 | layer = DatabaseFunctionalLayer |
1716 | |
1717 | def setUp(self): |
1718 | - super(TestVocabularyPickerWidget, self).setUp() |
1719 | + super().setUp() |
1720 | self.context = self.factory.makeTeam() |
1721 | self.vocabulary_registry = getVocabularyRegistry() |
1722 | self.vocabulary = self.vocabulary_registry.get( |
1723 | diff --git a/lib/lp/app/widgets/tests/test_suggestion.py b/lib/lp/app/widgets/tests/test_suggestion.py |
1724 | index cb1b031..6139a9d 100644 |
1725 | --- a/lib/lp/app/widgets/tests/test_suggestion.py |
1726 | +++ b/lib/lp/app/widgets/tests/test_suggestion.py |
1727 | @@ -84,7 +84,7 @@ class TestSuggestionWidget(TestCaseWithFactory): |
1728 | self.other_selection_widget.onKeyPress = on_key_press |
1729 | |
1730 | def setUp(self): |
1731 | - super(TestSuggestionWidget, self).setUp() |
1732 | + super().setUp() |
1733 | request = LaunchpadTestRequest() |
1734 | vocabulary = SimpleHugeVocabulary( |
1735 | [self.SAFE_TERM, self.UNSAFE_TERM]) |
1736 | @@ -234,13 +234,13 @@ class TestTargetGitRepositoryWidget(TestCaseWithFactory): |
1737 | owner = self.factory.makePerson() |
1738 | this_source, this_target = self.factory.makeGitRefs( |
1739 | owner=owner, target=owner, |
1740 | - paths=[u"refs/heads/source", u"refs/heads/target"]) |
1741 | + paths=["refs/heads/source", "refs/heads/target"]) |
1742 | bmp = self.factory.makeBranchMergeProposalForGit( |
1743 | source_ref=this_source, target_ref=this_target, |
1744 | date_created=datetime.now(utc) - timedelta(days=1)) |
1745 | other_source, other_target = self.factory.makeGitRefs( |
1746 | owner=owner, target=owner, |
1747 | - paths=[u"refs/heads/source", u"refs/heads/target"]) |
1748 | + paths=["refs/heads/source", "refs/heads/target"]) |
1749 | self.factory.makeBranchMergeProposalForGit( |
1750 | source_ref=other_source, target_ref=other_target, |
1751 | date_created=datetime.now(utc) - timedelta(days=1)) |
1752 | @@ -272,7 +272,7 @@ class TestTargetGitRepositoryWidget(TestCaseWithFactory): |
1753 | owner = self.factory.makePerson() |
1754 | source, target = self.factory.makeGitRefs( |
1755 | owner=owner, target=owner, |
1756 | - paths=[u"refs/heads/source", u"refs/heads/target"]) |
1757 | + paths=["refs/heads/source", "refs/heads/target"]) |
1758 | bmp = self.factory.makeBranchMergeProposalForGit( |
1759 | source_ref=source, target_ref=target, |
1760 | date_created=datetime.now(utc) - timedelta(days=1)) |
1761 | diff --git a/lib/lp/app/widgets/textwidgets.py b/lib/lp/app/widgets/textwidgets.py |
1762 | index f4dd12c..7657af2 100644 |
1763 | --- a/lib/lp/app/widgets/textwidgets.py |
1764 | +++ b/lib/lp/app/widgets/textwidgets.py |
1765 | @@ -3,7 +3,6 @@ |
1766 | |
1767 | import re |
1768 | |
1769 | -import six |
1770 | from zope.browserpage import ViewPageTemplateFile |
1771 | from zope.formlib.textwidgets import ( |
1772 | TextAreaWidget, |
1773 | @@ -42,14 +41,14 @@ class TokensTextWidget(StrippedTextWidget): |
1774 | else is replaced with a single space. |
1775 | """ |
1776 | normalised_text = re.sub(r'[^\w-]+', ' ', input) |
1777 | - return super(TokensTextWidget, self)._toFieldValue(normalised_text) |
1778 | + return super()._toFieldValue(normalised_text) |
1779 | |
1780 | |
1781 | class NoneableTextWidget(StrippedTextWidget): |
1782 | """A widget that that is None if it's value is empty or whitespace.""" |
1783 | |
1784 | def _toFieldValue(self, input): |
1785 | - value = super(NoneableTextWidget, self)._toFieldValue(input) |
1786 | + value = super()._toFieldValue(input) |
1787 | if value == '': |
1788 | return None |
1789 | else: |
1790 | @@ -63,13 +62,13 @@ class URIWidget(StrippedTextWidget): |
1791 | cssClass = 'urlTextType' |
1792 | |
1793 | def __init__(self, field, request): |
1794 | - super(URIWidget, self).__init__(field, request) |
1795 | + super().__init__(field, request) |
1796 | self.field = field |
1797 | |
1798 | def _toFieldValue(self, input): |
1799 | if isinstance(input, list): |
1800 | raise UnexpectedFormData('Only a single value is expected') |
1801 | - return super(URIWidget, self)._toFieldValue(input) |
1802 | + return super()._toFieldValue(input) |
1803 | |
1804 | |
1805 | class URIComponentWidget(LowerCaseTextWidget): |
1806 | @@ -106,17 +105,17 @@ class DelimitedListWidget(TextAreaWidget): |
1807 | |
1808 | def __init__(self, field, value_type, request): |
1809 | # We don't use value_type. |
1810 | - super(DelimitedListWidget, self).__init__(field, request) |
1811 | + super().__init__(field, request) |
1812 | |
1813 | # The default splitting function, which splits on |
1814 | # white-space. Subclasses can override this if different |
1815 | # delimiting rules are needed. |
1816 | - split = staticmethod(six.text_type.split) |
1817 | + split = staticmethod(str.split) |
1818 | |
1819 | # The default joining function, which simply separates each list |
1820 | # item with a newline. Subclasses can override this if different |
1821 | # delimiters are needed. |
1822 | - join = staticmethod(u'\n'.join) |
1823 | + join = staticmethod('\n'.join) |
1824 | |
1825 | def _toFormValue(self, value): |
1826 | """Converts a list to a newline separated string. |
1827 | @@ -134,7 +133,7 @@ class DelimitedListWidget(TextAreaWidget): |
1828 | By default, lists are displayed one item on a line: |
1829 | |
1830 | >>> names = ['fred', 'bob', 'harry'] |
1831 | - >>> six.ensure_str(widget._toFormValue(names)) |
1832 | + >>> widget._toFormValue(names) |
1833 | 'fred\\r\\nbob\\r\\nharry' |
1834 | """ |
1835 | if value == self.context.missing_value: |
1836 | @@ -143,7 +142,7 @@ class DelimitedListWidget(TextAreaWidget): |
1837 | value = self._missing |
1838 | else: |
1839 | value = self.join(value) |
1840 | - return super(DelimitedListWidget, self)._toFormValue(value) |
1841 | + return super()._toFormValue(value) |
1842 | |
1843 | def _toFieldValue(self, value): |
1844 | """Convert the input string into a list. |
1845 | @@ -166,8 +165,7 @@ class DelimitedListWidget(TextAreaWidget): |
1846 | 'bob' |
1847 | 'harry' |
1848 | """ |
1849 | - value = super( |
1850 | - DelimitedListWidget, self)._toFieldValue(value) |
1851 | + value = super()._toFieldValue(value) |
1852 | if value == self.context.missing_value: |
1853 | return value |
1854 | else: |
1855 | @@ -195,8 +193,7 @@ class NoneableDescriptionWidget(DescriptionWidget): |
1856 | """A widget that is None if it's value is empty or whitespace..""" |
1857 | |
1858 | def _toFieldValue(self, input): |
1859 | - value = super( |
1860 | - NoneableDescriptionWidget, self)._toFieldValue(input.strip()) |
1861 | + value = super()._toFieldValue(input.strip()) |
1862 | if value == '': |
1863 | return None |
1864 | else: |
Self-approving (mechanical).