From d77ce7b15591b2c86560927dd4fa9a3d41fbe28e Mon Sep 17 00:00:00 2001 From: David Muller Date: Mon, 29 Oct 2018 21:04:29 -0700 Subject: [PATCH] Make program and test suite compatible with Python 3 instead of Python 2. --- setup.py | 3 -- tests/test_ditem.py | 10 ++--- tests/test_dlist.py | 9 +--- tests/test_parsers.py | 19 +++----- tests/test_utils.py | 74 ++----------------------------- tests/test_widgets.py | 61 ++++++++++++------------- youtube_dl_gui/__init__.py | 9 +--- youtube_dl_gui/__main__.py | 6 --- youtube_dl_gui/downloaders.py | 25 +++++------ youtube_dl_gui/downloadmanager.py | 17 +++---- youtube_dl_gui/formats.py | 2 - youtube_dl_gui/info.py | 2 - youtube_dl_gui/logmanager.py | 9 +--- youtube_dl_gui/mainframe.py | 48 +++++++++----------- youtube_dl_gui/optionsframe.py | 40 ++++++++--------- youtube_dl_gui/optionsmanager.py | 10 +---- youtube_dl_gui/parsers.py | 5 --- youtube_dl_gui/updatemanager.py | 10 +---- youtube_dl_gui/utils.py | 48 +++++++++----------- youtube_dl_gui/version.py | 4 -- youtube_dl_gui/widgets.py | 27 ++++++----- 21 files changed, 143 insertions(+), 295 deletions(-) diff --git a/setup.py b/setup.py index ac68b9e9..a6857ca6 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtube-dlg setup file. Examples: diff --git a/tests/test_ditem.py b/tests/test_ditem.py index c6f09e8b..88b678af 100644 --- a/tests/test_ditem.py +++ b/tests/test_ditem.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - """Contains test cases for the DownloadItem object.""" -from __future__ import unicode_literals - import sys import os.path import unittest @@ -15,7 +10,7 @@ try: from youtube_dl_gui.downloadmanager import DownloadItem except ImportError as error: - print error + print(error) sys.exit(1) @@ -32,7 +27,8 @@ def test_init(self): self.assertEqual(ditem.stage, "Queued") self.assertEqual(ditem.url, url) self.assertEqual(ditem.options, options) - self.assertEqual(ditem.object_id, hash(url + unicode(options))) + # Python 3 has large hash; limit to C long + self.assertEqual(ditem.object_id, int(str(hash(url + str(options)))[:9])) self.assertEqual(ditem.path, "") self.assertEqual(ditem.filenames, []) diff --git a/tests/test_dlist.py b/tests/test_dlist.py index 8d38fa7d..c9c74b28 100644 --- a/tests/test_dlist.py +++ b/tests/test_dlist.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - """Contains test cases for the DownloadList object.""" -from __future__ import unicode_literals - import sys import os.path import unittest @@ -13,10 +8,10 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(PATH))) try: - import mock + import unittest.mock as mock from youtube_dl_gui.downloadmanager import DownloadList, synchronized except ImportError as error: - print error + print(error) sys.exit(1) diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 0c98c6ca..144159f1 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - """Contains test cases for the parsers module.""" -from __future__ import unicode_literals - import sys import os.path import unittest @@ -15,7 +10,7 @@ try: from youtube_dl_gui.parsers import OptionsParser except ImportError as error: - print error + print(error) sys.exit(1) @@ -39,7 +34,7 @@ def setUp(self): def check_options_parse(self, expected_options): options_parser = OptionsParser() - self.assertItemsEqual(options_parser.parse(self.options_dict), expected_options) + self.assertEqual(sorted(options_parser.parse(self.options_dict)), sorted(expected_options)) def test_parse_to_audio_requirement_bug(self): """Test case for the 'to_audio' requirement.""" @@ -56,7 +51,7 @@ def test_parse_to_audio_requirement_bug(self): "--audio-quality", "9", "-o", - "/home/user/Workplace/test/youtube/%(title)s.%(ext)s"] + os.path.join("/home/user/Workplace/test/youtube", "%(title)s.%(ext)s")] self.check_options_parse(expected_cmd_list) @@ -82,7 +77,7 @@ def test_parse_cmd_args_with_quotes(self): "-f", "mp4", "-o", - "/home/user/Workplace/test/youtube/%(title)s.%(ext)s", + os.path.join("/home/user/Workplace/test/youtube", "%(title)s.%(ext)s"), "--recode-video", "mkv", "--postprocessor-args", @@ -98,7 +93,7 @@ def test_parse_cmd_args_with_quotes(self): "-f", "mp4", "-o", - "/home/user/Workplace/test/youtube/%(title)s.%(ext)s", + os.path.join("/home/user/Workplace/test/youtube", "%(title)s.%(ext)s"), "--postprocessor-args", "-y -report"] @@ -112,7 +107,7 @@ def test_parse_cmd_args_with_quotes(self): "-f", "mp4", "-o", - "/home/user/Workplace/test/youtube/%(title)s.%(ext)s", + os.path.join("/home/user/Workplace/test/youtube", "%(title)s.%(ext)s"), "--postprocessor-args", "-y", "-v"] @@ -126,7 +121,7 @@ def test_parse_cmd_args_with_quotes(self): expected_cmd_list = ["--newline", "-o", - "/home/user/Workplace/test/youtube/%(title)s.%(ext)s", + os.path.join("/home/user/Workplace/test/youtube", "%(title)s.%(ext)s"), "-f", "(mp4)[width<1300]"] diff --git a/tests/test_utils.py b/tests/test_utils.py index 38936b57..49f2f723 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - """Contains test cases for the utils.py module.""" -from __future__ import unicode_literals - import sys import os.path import unittest @@ -13,11 +8,11 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(PATH))) try: - import mock + import unittest.mock as mock from youtube_dl_gui import utils except ImportError as error: - print error + print(error) sys.exit(1) @@ -111,70 +106,7 @@ def test_build_command_without_spaces_windows(self): self.run_tests("youtube-dl.exe", tmpl) - -class TestConvertItem(unittest.TestCase): - - """Test case for the convert_item function.""" - - def setUp(self): - self.input_list_u = ["v1", "v2", "v3"] - self.input_list_s = [str("v1"), str("v2"), str("v3")] - - self.input_tuple_u = ("v1", "v2", "v3") - self.input_tuple_s = (str("v1"), str("v2"), str("v3")) - - self.input_dict_u = {"k1": "v1", "k2": "v2"} - self.input_dict_s = {str("k1"): str("v1"), str("k2"): str("v2")} - - def check_iter(self, iterable, iter_type, is_unicode): - check_type = unicode if is_unicode else str - - iterable = utils.convert_item(iterable, is_unicode) - - self.assertIsInstance(iterable, iter_type) - - for item in iterable: - if iter_type == dict: - self.assertIsInstance(iterable[item], check_type) - - self.assertIsInstance(item, check_type) - - def test_convert_item_unicode_str(self): - self.assertIsInstance(utils.convert_item("test"), str) - - def test_convert_item_unicode_unicode(self): - self.assertIsInstance(utils.convert_item("test", True), unicode) - - def test_convert_item_str_unicode(self): - self.assertIsInstance(utils.convert_item(str("test"), True), unicode) - - def test_convert_item_str_str(self): - self.assertIsInstance(utils.convert_item(str("test")), str) - - def test_convert_item_list_empty(self): - self.assertEqual(len(utils.convert_item([])), 0) - - def test_convert_item_dict_empty(self): - self.assertEqual(len(utils.convert_item({})), 0) - - def test_convert_item_list_unicode_str(self): - self.check_iter(self.input_list_u, list, False) - - def test_convert_item_list_str_unicode(self): - self.check_iter(self.input_list_s, list, True) - - def test_convert_item_tuple_unicode_str(self): - self.check_iter(self.input_tuple_u, tuple, False) - - def test_convert_item_tuple_str_unicode(self): - self.check_iter(self.input_tuple_s, tuple, True) - - def test_convert_item_dict_unicode_str(self): - self.check_iter(self.input_dict_u, dict, False) - - def test_convert_item_dict_str_unicode(self): - self.check_iter(self.input_dict_s, dict, True) - +# removed TestConvertItem for Python 3, as str is unicode class TestGetDefaultLang(unittest.TestCase): diff --git a/tests/test_widgets.py b/tests/test_widgets.py index 7c8cb035..352a7d27 100644 --- a/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - """Contains test cases for the widgets.py module.""" -from __future__ import unicode_literals - import sys import os.path import unittest @@ -15,7 +10,7 @@ try: import wx - import mock + import unittest.mock as mock from youtube_dl_gui.widgets import ( ListBoxWithHeaders, @@ -23,7 +18,7 @@ ListBoxPopup ) except ImportError as error: - print error + print(error) sys.exit(1) @@ -38,7 +33,7 @@ def setUp(self): self.listbox = ListBoxWithHeaders(self.frame) self.listbox.add_header("Header") - self.listbox.add_items(["item%s" % i for i in xrange(10)]) + self.listbox.add_items(["item%s" % i for i in range(10)]) def tearDown(self): self.frame.Destroy() @@ -56,24 +51,24 @@ def test_find_string_item_not_found(self): self.assertEqual(self.listbox.FindString("item"), wx.NOT_FOUND) def test_get_string_header(self): - self.assertEqual(self.listbox.GetString(0), "Header") + self.assertEqual(self.listbox.GetString(0).strip(), "Header") def test_get_string_item(self): - self.assertEqual(self.listbox.GetString(10), "item9") + self.assertEqual(self.listbox.GetString(10).strip(), "item9") def test_get_string_item_not_found(self): - self.assertEqual(self.listbox.GetString(11), "") + self.assertEqual(self.listbox.GetString(11).strip(), "") def test_get_string_item_negative_index(self): - self.assertEqual(self.listbox.GetString(-1), "") + self.assertEqual(self.listbox.GetString(-1).strip(), "") def test_insert_items(self): self.listbox.SetSelection(1) self.listbox.InsertItems(["new_item1", "new_item2"], 1) - self.assertEqual(self.listbox.GetString(1), "new_item1") - self.assertEqual(self.listbox.GetString(2), "new_item2") - self.assertEqual(self.listbox.GetString(3), "item0") + self.assertEqual(self.listbox.GetString(1).strip(), "new_item1") + self.assertEqual(self.listbox.GetString(2).strip(), "new_item2") + self.assertEqual(self.listbox.GetString(3).strip(), "item0") self.assertTrue(self.listbox.IsSelected(3)) # Old selection + 2 @@ -94,11 +89,11 @@ def test_set_selection_item_invalid_index(self): def test_set_string_item(self): self.listbox.SetString(1, "item_mod0") - self.assertEqual(self.listbox.GetString(1), "item_mod0") + self.assertEqual(self.listbox.GetString(1).strip(), "item_mod0") def test_set_string_header(self): self.listbox.SetString(0, "New header") - self.assertEqual(self.listbox.GetString(0), "New header") + self.assertEqual(self.listbox.GetString(0).strip(), "New header") # Make sure that the header is not selectable self.listbox.SetSelection(0) @@ -123,12 +118,12 @@ def test_get_string_selection_empty(self): def test_append(self): self.listbox.Append("item666") - self.assertEqual(self.listbox.GetString(11), "item666") + self.assertEqual(self.listbox.GetString(11).strip(), "item666") def test_append_items(self): self.listbox.AppendItems(["new_item1", "new_item2"]) - self.assertEqual(self.listbox.GetString(11), "new_item1") - self.assertEqual(self.listbox.GetString(12), "new_item2") + self.assertEqual(self.listbox.GetString(11).strip(), "new_item1") + self.assertEqual(self.listbox.GetString(12).strip(), "new_item2") def test_clear(self): self.listbox.Clear() @@ -136,7 +131,7 @@ def test_clear(self): def test_delete(self): self.listbox.Delete(0) - self.assertEqual(self.listbox.GetString(0), "item0") + self.assertEqual(self.listbox.GetString(0).strip(), "item0") # Test item selection self.listbox.SetSelection(0) @@ -182,7 +177,7 @@ def setUp(self): # Call directly the ListBoxWithHeaders methods self.combobox.listbox.GetControl().add_header("Header") - self.combobox.listbox.GetControl().add_items(["item%s" % i for i in xrange(10)]) + self.combobox.listbox.GetControl().add_items(["item%s" % i for i in range(10)]) def tearDown(self): self.frame.Destroy() @@ -190,7 +185,7 @@ def tearDown(self): def test_init(self): combobox = CustomComboBox(self.frame, -1, "item1", choices=["item0", "item1", "item2"]) - self.assertEqual(combobox.GetValue(), "item1") + self.assertEqual(combobox.GetValue().strip(), "item1") self.assertEqual(combobox.GetCount(), 3) self.assertEqual(combobox.GetSelection(), 1) @@ -215,27 +210,27 @@ def test_is_text_empty_true(self): def test_set_selection_item(self): self.combobox.SetSelection(1) self.assertEqual(self.combobox.GetSelection(), 1) - self.assertEqual(self.combobox.GetValue(), "item0") + self.assertEqual(self.combobox.GetValue().strip(), "item0") def test_set_selection_header(self): self.combobox.SetSelection(0) self.assertEqual(self.combobox.GetSelection(), wx.NOT_FOUND) - self.assertEqual(self.combobox.GetValue(), "") + self.assertEqual(self.combobox.GetValue().strip(), "") def test_set_string_selection_item(self): self.combobox.SetStringSelection("item0") - self.assertEqual(self.combobox.GetStringSelection(), "item0") - self.assertEqual(self.combobox.GetValue(), "item0") + self.assertEqual(self.combobox.GetStringSelection().strip(), "item0") + self.assertEqual(self.combobox.GetValue().strip(), "item0") def test_set_string_selection_header(self): self.combobox.SetStringSelection("Header") - self.assertEqual(self.combobox.GetStringSelection(), "") - self.assertEqual(self.combobox.GetValue(), "") + self.assertEqual(self.combobox.GetStringSelection().strip(), "") + self.assertEqual(self.combobox.GetValue().strip(), "") def test_set_string_selection_invalid_string(self): self.combobox.SetStringSelection("abcde") - self.assertEqual(self.combobox.GetStringSelection(), "") - self.assertEqual(self.combobox.GetValue(), "") + self.assertEqual(self.combobox.GetStringSelection().strip(), "") + self.assertEqual(self.combobox.GetValue().strip(), "") # wx.ItemContainer methods @@ -256,13 +251,13 @@ def test_append_items(self): def test_delete(self): self.combobox.Delete(1) - self.assertEqual(self.combobox.GetString(1), "item1") + self.assertEqual(self.combobox.GetString(1).strip(), "item1") # wx.TextEntry methods def test_get_value(self): self.combobox.SetValue("value") - self.assertEqual(self.combobox.GetValue(), "value") + self.assertEqual(self.combobox.GetValue().strip(), "value") def main(): diff --git a/youtube_dl_gui/__init__.py b/youtube_dl_gui/__init__.py index d8c0fe2b..2d25727a 100644 --- a/youtube_dl_gui/__init__.py +++ b/youtube_dl_gui/__init__.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg __init__ file. Responsible on how the package looks from the outside. @@ -14,8 +11,6 @@ """ -from __future__ import unicode_literals - import sys import gettext import os.path @@ -23,7 +18,7 @@ try: import wx except ImportError as error: - print error + print(error) sys.exit(1) __packagename__ = "youtube_dl_gui" @@ -69,7 +64,7 @@ locale_dir = get_locale_file() try: - gettext.translation(__packagename__, locale_dir, [opt_manager.options['locale_name']]).install(unicode=True) + gettext.translation(__packagename__, locale_dir, [str(opt_manager.options['locale_name'])]).install(unicode=True) except IOError: opt_manager.options['locale_name'] = 'en_US' gettext.install(__packagename__) diff --git a/youtube_dl_gui/__main__.py b/youtube_dl_gui/__main__.py index 38b8acff..a1e57f86 100644 --- a/youtube_dl_gui/__main__.py +++ b/youtube_dl_gui/__main__.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg __main__ file. __main__ file is a python 'executable' file which calls the youtubedlg @@ -22,8 +19,6 @@ """ -from __future__ import unicode_literals - import sys if __package__ is None and not hasattr(sys, "frozen"): @@ -34,6 +29,5 @@ import youtube_dl_gui - if __name__ == '__main__': youtube_dl_gui.main() diff --git a/youtube_dl_gui/downloaders.py b/youtube_dl_gui/downloaders.py index 159ed6c0..449b38ef 100644 --- a/youtube_dl_gui/downloaders.py +++ b/youtube_dl_gui/downloaders.py @@ -1,14 +1,13 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Python module to download videos. This module contains the actual downloaders responsible for downloading the video files. -""" +Note: + downloaders.py is part of the youtubedlg package but it can be used + as a stand alone module for downloading videos. -from __future__ import unicode_literals +""" import re import os @@ -18,7 +17,7 @@ import subprocess from time import sleep -from Queue import Queue +from queue import Queue from threading import Thread from .utils import convert_item @@ -35,7 +34,7 @@ class PipeReader(Thread): Args: queue (Queue.Queue): Python queue to store the output of the subprocess. - + Warnings: All the operations are based on 'str' types. The caller has to convert the queued items back to 'unicode' if he needs to. @@ -58,9 +57,9 @@ def run(self): while self._running: if self._filedescriptor is not None: - for line in iter(self._filedescriptor.readline, str('')): + for line in iter(self._filedescriptor.readline, b''): # Ignore ffmpeg stderr - if str('ffmpeg version') in line: + if b'ffmpeg version' in line: ignore_line = True if not ignore_line: @@ -161,13 +160,13 @@ def download(self, url, options): cmd = self._get_cmd(url, options) self._create_process(cmd) - + if self._proc is not None: self._stderr_reader.attach_filedescriptor(self._proc.stderr) while self._proc_is_alive(): stdout = self._proc.stdout.readline().rstrip() - stdout = convert_item(stdout, to_unicode=True) + stdout = convert_item(stdout, to_unicode=False) if stdout: data_dict = extract_data(stdout) @@ -178,7 +177,7 @@ def download(self, url, options): # We don't need to read stderr in real time while not self._stderr_queue.empty(): stderr = self._stderr_queue.get_nowait().rstrip() - stderr = convert_item(stderr, to_unicode=True) + stderr = convert_item(stderr, to_unicode=False) self._log(stderr) @@ -342,7 +341,7 @@ def _create_process(self, cmd): # Encode command for subprocess # Refer to http://stackoverflow.com/a/9951851/35070 if sys.version_info < (3, 0): - cmd = convert_item(cmd, to_unicode=False) + cmd = convert_item(cmd, to_unicode=True) try: self._proc = subprocess.Popen(cmd, diff --git a/youtube_dl_gui/downloadmanager.py b/youtube_dl_gui/downloadmanager.py index a344829f..17843057 100644 --- a/youtube_dl_gui/downloadmanager.py +++ b/youtube_dl_gui/downloadmanager.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module for managing the download process. This module is responsible for managing the download process @@ -19,8 +16,6 @@ """ -from __future__ import unicode_literals - import time import os.path @@ -31,7 +26,6 @@ ) from wx import CallAfter -from wx.lib.pubsub import setuparg1 from wx.lib.pubsub import pub as Publisher from .parsers import OptionsParser @@ -95,7 +89,8 @@ class DownloadItem(object): def __init__(self, url, options): self.url = url self.options = options - self.object_id = hash(url + to_string(options)) + # Python 3 has large hash; limit to C long + self.object_id = int(str(hash(url + to_string(options)))[:9]) self.reset() @@ -166,7 +161,7 @@ def update_stats(self, stats_dict): if key in self.progress_stats: value = stats_dict[key] - if not isinstance(value, basestring) or not value: + if not isinstance(value, str) or not value: self.progress_stats[key] = self.default_values[key] else: self.progress_stats[key] = value @@ -380,7 +375,7 @@ def __init__(self, parent, download_list, opt_manager, log_manager=None): # Init the custom workers thread pool log_lock = None if log_manager is None else Lock() wparams = (opt_manager, self._youtubedl_path(), log_manager, log_lock) - self._workers = [Worker(*wparams) for _ in xrange(opt_manager.options["workers_number"])] + self._workers = [Worker(*wparams) for _ in range(opt_manager.options["workers_number"])] self.start() @@ -502,7 +497,7 @@ def _talk_to_gui(self, data): downloads using the active() method. """ - CallAfter(Publisher.sendMessage, MANAGER_PUB_TOPIC, data) + CallAfter(Publisher.sendMessage, MANAGER_PUB_TOPIC, msg=data) def _check_youtubedl(self): """Check if youtube-dl binary exists. If not try to download it. """ @@ -755,5 +750,5 @@ def _talk_to_gui(self, signal, data): if signal == 'receive': self._wait_for_reply = True - CallAfter(Publisher.sendMessage, WORKER_PUB_TOPIC, (signal, data)) + CallAfter(Publisher.sendMessage, WORKER_PUB_TOPIC, msg=(signal, data)) diff --git a/youtube_dl_gui/formats.py b/youtube_dl_gui/formats.py index e41e3df1..cfcb7f62 100644 --- a/youtube_dl_gui/formats.py +++ b/youtube_dl_gui/formats.py @@ -1,5 +1,3 @@ -# -*- coding: UTF-8 -*- - import gettext from .utils import TwoWayOrderedDict as tdict diff --git a/youtube_dl_gui/info.py b/youtube_dl_gui/info.py index 8b9e3bd3..05590573 100644 --- a/youtube_dl_gui/info.py +++ b/youtube_dl_gui/info.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """Youtubedlg module that holds package information. Note: diff --git a/youtube_dl_gui/logmanager.py b/youtube_dl_gui/logmanager.py index 86e5834c..7c1117fb 100644 --- a/youtube_dl_gui/logmanager.py +++ b/youtube_dl_gui/logmanager.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module responsible for handling the log stuff. """ -from __future__ import unicode_literals - import os.path from time import strftime @@ -64,7 +59,7 @@ def log(self, data): data (string): String to write to the log file. """ - if isinstance(data, basestring): + if isinstance(data, str): self._write(data + '\n', 'a') def _write(self, data, mode): @@ -85,7 +80,7 @@ def _write(self, data, mode): else: msg = data - log.write(msg.encode(self._encoding, 'ignore')) + log.write(str(msg.encode(self._encoding, 'ignore'))) def _init_log(self): """Initialize the log file if not exist. """ diff --git a/youtube_dl_gui/mainframe.py b/youtube_dl_gui/mainframe.py index e0aceaf7..80230815 100644 --- a/youtube_dl_gui/mainframe.py +++ b/youtube_dl_gui/mainframe.py @@ -1,15 +1,9 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module responsible for the main app window. """ -from __future__ import unicode_literals - import os import gettext import wx -from wx.lib.pubsub import setuparg1 #NOTE Should remove deprecated from wx.lib.pubsub import pub as Publisher from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin @@ -484,7 +478,7 @@ def _update_videoformat_combobox(self): self._videoformat_combobox.add_header(_("Audio")) self._videoformat_combobox.add_items(aformats) - current_index = self._videoformat_combobox.FindString(FORMATS[self.opt_manager.options["selected_format"]]) + current_index = self._videoformat_combobox.FindString(FORMATS[self.opt_manager.options["selected_format"]].strip()) if current_index == wx.NOT_FOUND: self._videoformat_combobox.SetSelection(0) @@ -494,7 +488,7 @@ def _update_videoformat_combobox(self): self._update_videoformat(None) def _update_videoformat(self, event): - self.opt_manager.options["selected_format"] = selected_format = FORMATS[self._videoformat_combobox.GetValue()] + self.opt_manager.options["selected_format"] = selected_format = FORMATS[self._videoformat_combobox.GetValue().strip()] if selected_format in VIDEO_FORMATS: self.opt_manager.options["video_format"] = selected_format @@ -801,7 +795,7 @@ def _set_layout(self): top_sizer = wx.BoxSizer(wx.HORIZONTAL) top_sizer.Add(self._url_text, 0, wx.ALIGN_BOTTOM | wx.BOTTOM, 5) - top_sizer.AddSpacer((-1, -1), 1) + top_sizer.AddSpacer(-1) top_sizer.Add(self._settings_button) panel_sizer.Add(top_sizer, 0, wx.EXPAND) @@ -809,13 +803,13 @@ def _set_layout(self): mid_sizer = wx.BoxSizer(wx.HORIZONTAL) mid_sizer.Add(self._folder_icon) - mid_sizer.AddSpacer((3, -1)) + mid_sizer.AddSpacer(3) mid_sizer.Add(self._path_combobox, 2, wx.ALIGN_CENTER_VERTICAL) - mid_sizer.AddSpacer((5, -1)) + mid_sizer.AddSpacer(5) mid_sizer.Add(self._buttons["savepath"], flag=wx.ALIGN_CENTER_VERTICAL) - mid_sizer.AddSpacer((10, -1), 1) + mid_sizer.AddSpacer(10) mid_sizer.Add(self._videoformat_combobox, 1, wx.ALIGN_CENTER_VERTICAL) - mid_sizer.AddSpacer((5, -1)) + mid_sizer.AddSpacer(5) mid_sizer.Add(self._buttons["add"], flag=wx.ALIGN_CENTER_VERTICAL) panel_sizer.Add(mid_sizer, 0, wx.EXPAND | wx.ALL, 10) @@ -824,17 +818,17 @@ def _set_layout(self): bottom_sizer = wx.BoxSizer(wx.HORIZONTAL) bottom_sizer.Add(self._buttons["delete"]) - bottom_sizer.AddSpacer((5, -1)) + bottom_sizer.AddSpacer(5) bottom_sizer.Add(self._buttons["play"]) - bottom_sizer.AddSpacer((5, -1)) + bottom_sizer.AddSpacer(5) bottom_sizer.Add(self._buttons["up"]) - bottom_sizer.AddSpacer((5, -1)) + bottom_sizer.AddSpacer(5) bottom_sizer.Add(self._buttons["down"]) - bottom_sizer.AddSpacer((5, -1)) + bottom_sizer.AddSpacer(5) bottom_sizer.Add(self._buttons["reload"]) - bottom_sizer.AddSpacer((5, -1)) + bottom_sizer.AddSpacer(5) bottom_sizer.Add(self._buttons["pause"]) - bottom_sizer.AddSpacer((10, -1), 1) + bottom_sizer.AddSpacer(10) bottom_sizer.Add(self._buttons["start"]) panel_sizer.Add(bottom_sizer, 0, wx.EXPAND | wx.TOP, 5) @@ -913,7 +907,7 @@ def _download_worker_handler(self, msg): See downloadmanager.Worker _talk_to_gui() method. """ - signal, data = msg.data + signal, data = msg download_item = self._download_list.get_item(data["index"]) download_item.update_stats(data) @@ -930,7 +924,7 @@ def _download_manager_handler(self, msg): See downloadmanager.DownloadManager _talk_to_gui() method. """ - data = msg.data + data = msg if data == 'finished': self._print_stats() @@ -1140,7 +1134,7 @@ def has_url(self, url): return url in self._url_list def bind_item(self, download_item): - self.InsertStringItem(self._list_index, download_item.url) + self.InsertItem(self._list_index, download_item.url) self.SetItemData(self._list_index, download_item.object_id) @@ -1160,9 +1154,9 @@ def _update_from_item(self, row, download_item): progress_stats["playlist_index"], progress_stats["playlist_size"]) - self.SetStringItem(row, column, status) + self.SetItem(row, column, status) else: - self.SetStringItem(row, column, progress_stats[key]) + self.SetItem(row, column, progress_stats[key]) def clear(self): """Clear the ListCtrl widget & reset self._list_index and @@ -1179,10 +1173,10 @@ def get_selected(self): return self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED) def get_all_selected(self): - return [index for index in xrange(self._list_index) if self.IsSelected(index)] + return [index for index in range(self._list_index) if self.IsSelected(index)] def deselect_all(self): - for index in xrange(self._list_index): + for index in range(self._list_index): self.Select(index, on=0) def get_next_selected(self, start=-1, reverse=False): @@ -1198,7 +1192,7 @@ def get_next_selected(self, start=-1, reverse=False): end = -1 if reverse else self._list_index step = -1 if reverse else 1 - for index in xrange(start, end, step): + for index in range(start, end, step): if self.IsSelected(index): return index diff --git a/youtube_dl_gui/optionsframe.py b/youtube_dl_gui/optionsframe.py index ab278ebe..b438ced2 100644 --- a/youtube_dl_gui/optionsframe.py +++ b/youtube_dl_gui/optionsframe.py @@ -1,15 +1,11 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module responsible for the options window. """ -from __future__ import unicode_literals - import os import gettext import wx -import wx.combo +from wx import ComboBox +from wx.adv import BitmapComboBox from wx.lib.art import flagart from .utils import ( @@ -98,7 +94,7 @@ def _set_layout(self): buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) buttons_sizer.Add(self.reset_button) - buttons_sizer.AddSpacer((5, -1)) + buttons_sizer.AddSpacer(5) buttons_sizer.Add(self.close_button) main_sizer.Add(buttons_sizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5) @@ -208,7 +204,7 @@ def crt_textctrl(self, style=None): return textctrl def crt_combobox(self, choices, size=(-1, -1), event_handler=None): - combobox = wx.ComboBox(self, choices=choices, size=size, style=wx.CB_READONLY) + combobox = ComboBox(self, choices=choices, size=size, style=wx.CB_READONLY) if event_handler is not None: combobox.Bind(wx.EVT_COMBOBOX, event_handler) @@ -216,7 +212,7 @@ def crt_combobox(self, choices, size=(-1, -1), event_handler=None): return combobox def crt_bitmap_combobox(self, choices, size=(-1, -1), event_handler=None): - combobox = wx.combo.BitmapComboBox(self, size=size, style=wx.CB_READONLY) + combobox = BitmapComboBox(self, size=size, style=wx.CB_READONLY) for item in choices: lang_code, lang_name = item @@ -348,7 +344,7 @@ def _set_layout(self): custom_format_sizer = wx.BoxSizer(wx.HORIZONTAL) custom_format_sizer.Add(self.filename_custom_format, 1, wx.ALIGN_CENTER_VERTICAL) - custom_format_sizer.AddSpacer((5, -1)) + custom_format_sizer.AddSpacer(5) custom_format_sizer.Add(self.filename_custom_format_button) vertical_sizer.Add(custom_format_sizer, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) @@ -363,7 +359,7 @@ def _set_layout(self): shutdown_sizer = wx.BoxSizer(wx.HORIZONTAL) shutdown_sizer.Add(self.shutdown_checkbox) - shutdown_sizer.AddSpacer((-1, -1), 1) + shutdown_sizer.AddSpacer(-1) shutdown_sizer.Add(self.sudo_textctrl, 1) vertical_sizer.Add(shutdown_sizer, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) @@ -500,7 +496,7 @@ def _set_layout(self): audio_quality_sizer = wx.BoxSizer(wx.HORIZONTAL) audio_quality_sizer.Add(self.audio_quality_label, flag=wx.ALIGN_CENTER_VERTICAL) - audio_quality_sizer.AddSpacer((20, -1)) + audio_quality_sizer.AddSpacer(20) audio_quality_sizer.Add(self.audio_quality_combobox) vertical_sizer.Add(audio_quality_sizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) @@ -610,7 +606,7 @@ def _set_layout(self): plist_and_fsize_sizer = wx.BoxSizer(wx.HORIZONTAL) plist_and_fsize_sizer.Add(self._build_playlist_sizer(), 1, wx.EXPAND) - plist_and_fsize_sizer.AddSpacer((5, -1)) + plist_and_fsize_sizer.AddSpacer(5) plist_and_fsize_sizer.Add(self._build_filesize_sizer(), 1, wx.EXPAND) vertical_sizer.Add(plist_and_fsize_sizer, 1, wx.EXPAND | wx.TOP, border=5) @@ -620,7 +616,7 @@ def _set_layout(self): def _build_playlist_sizer(self): playlist_box_sizer = wx.StaticBoxSizer(self.playlist_box, wx.VERTICAL) - playlist_box_sizer.AddSpacer((-1, 10)) + playlist_box_sizer.AddSpacer(10) border = wx.GridBagSizer(5, 40) @@ -760,7 +756,7 @@ def _set_layout(self): # Set up retries box retries_sizer = wx.BoxSizer(wx.HORIZONTAL) retries_sizer.Add(self.retries_label, flag=wx.ALIGN_CENTER_VERTICAL) - retries_sizer.AddSpacer((20, -1)) + retries_sizer.AddSpacer(20) retries_sizer.Add(self.retries_spinctrl) vertical_sizer.Add(retries_sizer, flag=wx.ALIGN_RIGHT | wx.TOP | wx.RIGHT, border=5) @@ -801,9 +797,9 @@ def _set_layout(self): logging_sizer = wx.BoxSizer(wx.HORIZONTAL) logging_sizer.Add(self.enable_log_checkbox) - logging_sizer.AddSpacer((-1, -1), 1) + logging_sizer.AddSpacer(-1) logging_sizer.Add(self.view_log_button) - logging_sizer.AddSpacer((5, -1)) + logging_sizer.AddSpacer(5) logging_sizer.Add(self.clear_log_button) vertical_sizer.Add(logging_sizer, flag=wx.EXPAND | wx.ALL, border=5) @@ -856,7 +852,7 @@ def __init__(self, *args, **kwargs): super(ExtraTab, self).__init__(*args, **kwargs) self.cmdline_args_label = self.crt_statictext(_("Youtube-dl command line options (e.g. --help)")) - self.cmdline_args_textctrl = self.crt_textctrl(wx.TE_MULTILINE | wx.TE_LINEWRAP) + self.cmdline_args_textctrl = self.crt_textctrl(wx.TE_MULTILINE) self.extra_opts_label = self.crt_statictext(_("Extra options")) @@ -879,13 +875,13 @@ def _set_layout(self): extra_opts_sizer = wx.WrapSizer() extra_opts_sizer.Add(self.youtube_dl_debug_checkbox) - extra_opts_sizer.AddSpacer((5, -1)) + extra_opts_sizer.AddSpacer(5) extra_opts_sizer.Add(self.ignore_errors_checkbox) - extra_opts_sizer.AddSpacer((5, -1)) + extra_opts_sizer.AddSpacer(5) extra_opts_sizer.Add(self.ignore_config_checkbox) - extra_opts_sizer.AddSpacer((5, -1)) + extra_opts_sizer.AddSpacer(5) extra_opts_sizer.Add(self.no_mtime_checkbox) - extra_opts_sizer.AddSpacer((5, -1)) + extra_opts_sizer.AddSpacer(5) extra_opts_sizer.Add(self.native_hls_checkbox) vertical_sizer.Add(extra_opts_sizer, flag=wx.ALL, border=5) diff --git a/youtube_dl_gui/optionsmanager.py b/youtube_dl_gui/optionsmanager.py index fc354e4f..ee97a3dd 100644 --- a/youtube_dl_gui/optionsmanager.py +++ b/youtube_dl_gui/optionsmanager.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module to handle settings. """ -from __future__ import unicode_literals - import os import json @@ -327,12 +322,11 @@ def save_to_file(self): """Save options to settings file. """ check_path(self.config_path) - with open(self.settings_file, 'wb') as settings_file: + with open(self.settings_file, 'w') as settings_file: options = self._get_options() json.dump(options, settings_file, - indent=4, - separators=(',', ': ')) + indent=4) def _settings_are_valid(self, settings_dictionary): """Check settings.json dictionary. diff --git a/youtube_dl_gui/parsers.py b/youtube_dl_gui/parsers.py index dea0189f..37a013ac 100644 --- a/youtube_dl_gui/parsers.py +++ b/youtube_dl_gui/parsers.py @@ -1,10 +1,5 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module responsible for parsing the options. """ -from __future__ import unicode_literals - import os.path from .utils import ( diff --git a/youtube_dl_gui/updatemanager.py b/youtube_dl_gui/updatemanager.py index d0c5a8a4..5e47cc66 100644 --- a/youtube_dl_gui/updatemanager.py +++ b/youtube_dl_gui/updatemanager.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module to update youtube-dl binary. Attributes: @@ -9,14 +6,11 @@ """ -from __future__ import unicode_literals - import os.path from threading import Thread -from urllib2 import urlopen, URLError, HTTPError +from urllib.request import urlopen, URLError, HTTPError from wx import CallAfter -from wx.lib.pubsub import setuparg1 from wx.lib.pubsub import pub as Publisher from .utils import ( @@ -93,4 +87,4 @@ def _talk_to_gui(self, signal, data=None): 4) finish: The update thread is ready to join """ - CallAfter(Publisher.sendMessage, UPDATE_PUB_TOPIC, (signal, data)) + CallAfter(Publisher.sendMessage, UPDATE_PUB_TOPIC, msg=(signal, data)) diff --git a/youtube_dl_gui/utils.py b/youtube_dl_gui/utils.py index 729c0079..6cbec2ab 100644 --- a/youtube_dl_gui/utils.py +++ b/youtube_dl_gui/utils.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- - """Youtubedlg module that contains util functions. Attributes: @@ -10,8 +7,6 @@ """ -from __future__ import unicode_literals - import os import sys import json @@ -22,7 +17,7 @@ try: from twodict import TwoWayOrderedDict except ImportError as error: - print error + print(error) sys.exit(1) from .info import __appname__ @@ -64,13 +59,13 @@ def convert_item(item, to_unicode=False): types back to 'str'. """ - if to_unicode and isinstance(item, str): + if to_unicode and hasattr(item, 'encode'): # Convert str to unicode - return item.decode(get_encoding(), 'ignore') + return item.encode(get_encoding(), 'ignore') - if not to_unicode and isinstance(item, unicode): + if not to_unicode and hasattr(item, 'decode'): # Convert unicode to str - return item.encode(get_encoding(), 'ignore') + return item.decode(get_encoding(), 'ignore') if hasattr(item, '__iter__'): # Handle iterables @@ -106,15 +101,16 @@ def wrapper(*args, **kwargs): # See: https://github.com/MrS0m30n3/youtube-dl-gui/issues/57 # Patch os functions to convert between 'str' and 'unicode' on app bounds -os_sep = unicode(os.sep) -os_getenv = convert_on_bounds(os.getenv) -os_makedirs = convert_on_bounds(os.makedirs) -os_path_isdir = convert_on_bounds(os.path.isdir) -os_path_exists = convert_on_bounds(os.path.exists) -os_path_dirname = convert_on_bounds(os.path.dirname) -os_path_abspath = convert_on_bounds(os.path.abspath) -os_path_realpath = convert_on_bounds(os.path.realpath) -os_path_expanduser = convert_on_bounds(os.path.expanduser) +# not needed for Python 3 +os_sep = os.sep +os_getenv = os.getenv +os_makedirs = os.makedirs +os_path_isdir = os.path.isdir +os_path_exists = os.path.exists +os_path_dirname = os.path.dirname +os_path_abspath = os.path.abspath +os_path_realpath = os.path.realpath +os_path_expanduser = os.path.expanduser # Patch locale functions locale_getdefaultlocale = convert_on_bounds(locale.getdefaultlocale) @@ -382,10 +378,10 @@ def escape(option): def get_default_lang(): - """Get default language using the 'locale' module.""" - default_lang, _ = locale_getdefaultlocale() - - if not default_lang: - default_lang = "en_US" - - return default_lang + """Return the language. + + Returns: + The chosen language if present, or a default of 'en_US' if blank. + + """ + return locale_getdefaultlocale()[0] or 'en_US' diff --git a/youtube_dl_gui/version.py b/youtube_dl_gui/version.py index 0c1fe4a4..58d168b0 100644 --- a/youtube_dl_gui/version.py +++ b/youtube_dl_gui/version.py @@ -1,5 +1 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - __version__ = '0.4' diff --git a/youtube_dl_gui/widgets.py b/youtube_dl_gui/widgets.py index 4783016b..481ec961 100644 --- a/youtube_dl_gui/widgets.py +++ b/youtube_dl_gui/widgets.py @@ -1,14 +1,9 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - -from __future__ import unicode_literals - import sys try: import wx except ImportError as error: - print error + print(error) sys.exit(1) @@ -87,13 +82,13 @@ def _remove_prefix(self, string): # wx.ListBox methods def FindString(self, string): - index = super(ListBoxWithHeaders, self).FindString(string) - - if index == wx.NOT_FOUND: - # This time try with prefix - index = super(ListBoxWithHeaders, self).FindString(self._add_prefix(string)) - - return index + # self.GetString wasn't properly finding strings that were + # clearly in self.GetStrings() + content = list(map(str.strip, self.GetStrings())) + try: + return content.index(string.strip()) + except ValueError: + return -1 def GetStringSelection(self): return self._remove_prefix(super(ListBoxWithHeaders, self).GetStringSelection()) @@ -136,7 +131,11 @@ def SetStringSelection(self, string): # wx.ItemContainer methods def Append(self, string): - super(ListBoxWithHeaders, self).Append(self._add_prefix(string)) + if isinstance(string, str): # for strings + content = self._add_prefix(string) + else: # for lists + content = list(map(self._add_prefix, string)) + super(ListBoxWithHeaders, self).Append(content) def AppendItems(self, strings): strings = [self._add_prefix(string) for string in strings]