From 35ded20a8ee1392c731bd6a35f1f3a2d10897c92 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 04:31:08 +0800 Subject: [PATCH 1/9] test(test_main): skip test without attribute after fork --- mps_youtube/test/test_main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mps_youtube/test/test_main.py b/mps_youtube/test/test_main.py index 315e445c..72c1179d 100644 --- a/mps_youtube/test/test_main.py +++ b/mps_youtube/test/test_main.py @@ -1,17 +1,22 @@ import unittest + +import pytest + import mps_youtube.main as mps + class TestMain(unittest.TestCase): - def test_fmt_time(self): + pytest.skip('main not have tested attribute') self.assertEqual(mps.fmt_time(0), '00:00') self.assertEqual(mps.fmt_time(59), '00:59') self.assertEqual(mps.fmt_time(100), '01:40') self.assertEqual(mps.fmt_time(1000), '16:40') self.assertEqual(mps.fmt_time(5000), '83:20') self.assertEqual(mps.fmt_time(6500), '1:48:20') - + def test_num_repr(self): + pytest.skip('main not have tested attribute') self.assertEqual(mps.num_repr(0), '0') self.assertEqual(mps.num_repr(1001), '1001') self.assertEqual(mps.num_repr(10001), '10k') From 22b4564e618aceb49bad34428e45e9ecf25907e6 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 05:13:37 +0800 Subject: [PATCH 2/9] test: uea_pad --- mps_youtube/test/test_util.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 mps_youtube/test/test_util.py diff --git a/mps_youtube/test/test_util.py b/mps_youtube/test/test_util.py new file mode 100644 index 00000000..7a44b85e --- /dev/null +++ b/mps_youtube/test/test_util.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import pytest + +import mps_youtube.util as util + + +@pytest.mark.parametrize( + "num,t,exp_res", + ( + (0, "", ""), + (0, None, ""), + ), +) +def test_uea_pad(num, t, exp_res): + res = util.uea_pad(num, t) + assert res == exp_res From 1643266f21ccf7a99481a1615b4a53c4fbabc878 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 05:17:12 +0800 Subject: [PATCH 3/9] fix(util.uea_pad): handle AttributeError on t.split also isort import --- mps_youtube/util.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/mps_youtube/util.py b/mps_youtube/util.py index 1f7cc283..62d84782 100644 --- a/mps_youtube/util.py +++ b/mps_youtube/util.py @@ -1,23 +1,21 @@ +import collections +import ctypes +import json +import logging import os +import platform import re +import subprocess import sys -import ctypes -import logging import time -import subprocess -import collections import unicodedata import urllib -import json -import platform from datetime import datetime, timezone +from importlib import import_module - -from . import g, c, terminalsize, description_parser +from . import c, description_parser, g, terminalsize from .playlist import Video -from importlib import import_module - macos = platform.system() == "Darwin" mswin = os.name == "nt" @@ -292,7 +290,7 @@ def uea_pad(num, t, direction="<", notrunc=False): """ Right pad with spaces taking into account East Asian width chars. """ direction = direction.strip() or "<" - t = ' '.join(t.split('\n')) + t = " ".join(t.split("\n") if hasattr(t, "split") else []) # TODO: Find better way of dealing with this? if num <= 0: From 397eddd0146e04e95e6cc0598741bae8055a3e32 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 06:47:01 +0800 Subject: [PATCH 4/9] build(setup): add requests --- setup.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index dcf7ff5d..f761bb7f 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,8 @@ python setup.py sdist bdist_wheel """ -import sys, os +import os +import sys from datetime import datetime if sys.version_info < (3, 6): @@ -17,11 +18,11 @@ # with open("README.md", "r", encoding="utf-8") as fh: # long_description = fh.read() - + # with open("requirements.txt", "r", encoding="utf-8") as fh: # requirements = fh.readlines() - - + + options = dict( name="yewtube", version=datetime.utcnow().strftime('%y.%m.%d'), @@ -37,9 +38,10 @@ install_requires=[ 'pyreadline ; platform_system=="Linux"', 'pyreadline3 ; platform_system=="Windows"', - 'pyperclip', - 'youtube-search-python', - 'yt-dlp', + "pyperclip", + "pytest>=7.0.1", + "youtube-search-python", + "yt-dlp", ], classifiers=[ "Topic :: Utilities", @@ -86,6 +88,7 @@ if os.name == "nt": try: import py2exe + # Only setting these when py2exe imports successfully prevents warnings # in easy_install options['console'] = ['yt'] From dc4af721aa90fe79c492f9f1ae1f4a698049a085 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 07:05:57 +0800 Subject: [PATCH 5/9] refactor: reset to upstream --- mps_youtube/util.py | 20 +++++++++++--------- setup.py | 15 ++++++--------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/mps_youtube/util.py b/mps_youtube/util.py index 9a223d3a..40c17e54 100644 --- a/mps_youtube/util.py +++ b/mps_youtube/util.py @@ -1,21 +1,23 @@ -import collections -import ctypes -import json -import logging import os -import platform import re -import subprocess import sys +import ctypes +import logging import time +import subprocess +import collections import unicodedata import urllib +import json +import platform from datetime import datetime, timezone -from importlib import import_module -from . import c, description_parser, g, terminalsize + +from . import g, c, terminalsize, description_parser from .playlist import Video +from importlib import import_module + macos = platform.system() == "Darwin" mswin = os.name == "nt" @@ -290,7 +292,7 @@ def uea_pad(num, t, direction="<", notrunc=False): """ Right pad with spaces taking into account East Asian width chars. """ direction = direction.strip() or "<" - t = " ".join(str(t).split("\n")) + t = ' '.join(str(t).split('\n')) # TODO: Find better way of dealing with this? if num <= 0: diff --git a/setup.py b/setup.py index fc918de4..fbd62bb7 100755 --- a/setup.py +++ b/setup.py @@ -7,8 +7,7 @@ python setup.py sdist bdist_wheel """ -import os -import sys +import sys, os from datetime import datetime if sys.version_info < (3, 6): @@ -21,8 +20,8 @@ # with open("requirements.txt", "r", encoding="utf-8") as fh: # requirements = fh.readlines() - - + + options = dict( name="yewtube", version=datetime.now().strftime('%y%m.%d.%H'), @@ -39,10 +38,9 @@ 'requests', 'pyreadline ; platform_system=="Linux"', 'pyreadline3 ; platform_system=="Windows"', - "pyperclip", - "pytest>=7.0.1", - "youtube-search-python", - "yt-dlp", + 'pyperclip', + 'youtube-search-python', + 'yt-dlp', ], classifiers=[ "Topic :: Utilities", @@ -89,7 +87,6 @@ if os.name == "nt": try: import py2exe - # Only setting these when py2exe imports successfully prevents warnings # in easy_install options['console'] = ['yt'] From f40ca1a557974929da3cc0c599d1f9342b4cdfa9 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 07:08:56 +0800 Subject: [PATCH 6/9] ci: python-app --- .github/workflows/python-app.yml | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/python-app.yml diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 00000000..af61095a --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,36 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python application + +on: + push: + branches: [develop] + pull_request: + branches: [develop] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest From 3d117ad49ed8630873dd070f474e6641007fd01a Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Wed, 16 Feb 2022 07:43:29 +0800 Subject: [PATCH 7/9] ci(python-app): workflows based on origin/develop - only run pytest - use matrix for python version and os --- .github/workflows/python-app.yml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index af61095a..7c384e50 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -11,26 +11,22 @@ on: jobs: build: - - runs-on: ubuntu-latest - + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] steps: - uses: actions/checkout@v2 - - name: Set up Python 3.10 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: - python-version: '3.10' + python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + pip install pytest + pip install . - name: Test with pytest run: | pytest From 9c2350c87daed2a52460b4e9ad72ba4b11e7796f Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Thu, 17 Feb 2022 12:15:55 +0800 Subject: [PATCH 8/9] test(mplayer): _get_mplayer_version use default func behavior when no mplayer found --- mps_youtube/test/test_players_mplayer.py | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 mps_youtube/test/test_players_mplayer.py diff --git a/mps_youtube/test/test_players_mplayer.py b/mps_youtube/test/test_players_mplayer.py new file mode 100644 index 00000000..e3c12b3f --- /dev/null +++ b/mps_youtube/test/test_players_mplayer.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from unittest import mock + +import pytest + +from mps_youtube.players import mplayer + + +@pytest.mark.parametrize( + "exename, exp_err", + [ + ("", (OSError, PermissionError)), + ("mplayersomething", FileNotFoundError), + ], +) +def test_get_mplayer_version_no_mplayer(exename, exp_err): + with pytest.raises(exp_err): + mplayer._get_mplayer_version(exename) + + +def test_get_mplayer_version_invalid_input(): + with mock.patch("mps_youtube.players.mplayer.subprocess"), pytest.raises(TypeError): + mplayer._get_mplayer_version(mock.MagicMock()) + + +@pytest.mark.parametrize( + "output, exp_res", + [ + ( + "MPlayer Redxii-SVN-r38151-6.2.0 (x86_64) (C) 2000-2019 MPlayer Team...", + 38151, + ), + ("MPlayer SVN-r38151-6.2.0 (x86_64) (C) 2000-2019 MPlayer Team...", 38151), + ("MPlayer 1.4 (Debian), built with gcc-10 (C) 2000-2019 MPlayer Team", (1, 4)), + ], +) +def test_get_mplayer_version(output, exp_res): + with mock.patch("mps_youtube.players.mplayer.subprocess") as m_subprocess: + m_subprocess.check_output.return_value.decode.return_value = output + assert mplayer._get_mplayer_version(mock.MagicMock()) == exp_res From ab21c5d1bc872ed482bf482ad37949129c1e4f78 Mon Sep 17 00:00:00 2001 From: Rachmadani Haryono Date: Thu, 17 Feb 2022 12:19:52 +0800 Subject: [PATCH 9/9] fix(mplayer): _get_mplayer_version - isort module - type hint - function doc - return value type hint for func --- mps_youtube/players/mplayer.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/mps_youtube/players/mplayer.py b/mps_youtube/players/mplayer.py index ba40d5f8..a08e941f 100644 --- a/mps_youtube/players/mplayer.py +++ b/mps_youtube/players/mplayer.py @@ -1,11 +1,11 @@ import os +import re +import subprocess import sys import tempfile -import subprocess -import re - -from .. import g, screen, c, paths, config, util +import typing as T +from .. import c, config, g, paths, screen, util from ..player import CmdPlayer mswin = os.name == "nt" @@ -225,9 +225,27 @@ def _get_input_file(): return tmpfile.name -def _get_mplayer_version(exename): - o = subprocess.check_output([exename]).decode() - m = re.search('MPlayer SVN[\s-]r([0-9]+)', o, re.MULTILINE | re.IGNORECASE) +def _get_mplayer_version(exename: str) -> T.Union[int, T.Tuple[int, ...]]: + """get mplayer version. + + Args: + exename: mplayer executable name. + + Returns: + single integer value or tuple of mplayer version. Return `0` if failed + + Raises: + OSError: if `exename` is invalid + FileNotFoundError: if no mplayer found + PermissionError: if user dont have permission to run `exename` + TypeError: if `exename` return invalid type + """ + try: + o = subprocess.check_output([exename]).decode() + except FileNotFoundError as err: + util.dbg("%sFailed to detect mplayer version, exename %s,%s", c.r, exename, c.w) + raise err + m = re.search(r"MPlayer \S*?SVN[\s-]r([0-9]+)", o, re.MULTILINE | re.IGNORECASE) ver = 0 if m: