Hello community,
here is the log from the commit of package python-gTTS for openSUSE:Factory checked in at 2019-09-27 14:47:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-gTTS (Old)
and /work/SRC/openSUSE:Factory/.python-gTTS.new.2352 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-gTTS"
Fri Sep 27 14:47:03 2019 rev:4 rq:730386 version:2.0.4
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-gTTS/python-gTTS.changes 2019-02-11 21:28:19.710985272 +0100
+++ /work/SRC/openSUSE:Factory/.python-gTTS.new.2352/python-gTTS.changes 2019-09-27 14:47:05.064977577 +0200
@@ -1,0 +2,7 @@
+Thu Sep 12 11:46:16 UTC 2019 - Tomáš Chvátal
+
+- Update to 2.0.4:
+ * gTTS is now built as a wheel package (Python 2 & 3) (#181)
+- Rebase patch remove-pip-requirement.patch
+
+-------------------------------------------------------------------
Old:
----
gTTS-2.0.3.tar.gz
New:
----
gTTS-2.0.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-gTTS.spec ++++++
--- /var/tmp/diff_new_pack.7nyYFe/_old 2019-09-27 14:47:05.928975330 +0200
+++ /var/tmp/diff_new_pack.7nyYFe/_new 2019-09-27 14:47:05.948975278 +0200
@@ -18,21 +18,30 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-gTTS
-Version: 2.0.3
+Version: 2.0.4
Release: 0
Summary: Python module to create MP3 files from spoken text via the Google TTS API
License: MIT
Group: Development/Languages/Python
-Url: https://github.com/pndurette/gTTS
+URL: https://github.com/pndurette/gTTS
Source: https://files.pythonhosted.org/packages/source/g/gTTS/gTTS-%{version}.tar.gz
Patch0: remove-pip-requirement.patch
-BuildRequires: %{python_module setuptools}
+BuildRequires: %{python_module beautifulsoup4}
+BuildRequires: %{python_module click}
+BuildRequires: %{python_module gTTS-token >= 1.1.3}
+BuildRequires: %{python_module mock}
+BuildRequires: %{python_module pytest >= 3.9}
+BuildRequires: %{python_module requests}
+BuildRequires: %{python_module setuptools >= 38.6}
+BuildRequires: %{python_module six}
+BuildRequires: %{python_module testfixtures}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires: python-beautifulsoup4
Requires: python-click
-Requires: python-gTTS-token
+Requires: python-gTTS-token >= 1.1.3
Requires: python-requests
+Requires: python-setuptools
Requires: python-six
BuildArch: noarch
%python_subpackages
@@ -54,8 +63,11 @@
%python_install
%python_expand %fdupes %{buildroot}%{$python_sitelib}
+%check
+# tests are sadly mostly online
+#%%pytest
+
%files %{python_files}
-%defattr(-,root,root,-)
%doc CHANGELOG.rst README.md
%license LICENSE
%python3_only %{_bindir}/gtts-cli
++++++ gTTS-2.0.3.tar.gz -> gTTS-2.0.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/CHANGELOG.rst new/gTTS-2.0.4/CHANGELOG.rst
--- old/gTTS-2.0.3/CHANGELOG.rst 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/CHANGELOG.rst 2019-08-30 02:57:17.000000000 +0200
@@ -9,6 +9,27 @@
.. towncrier release notes start
+2.0.4 (2019-08-29)
+------------------
+
+Features
+~~~~~~~~
+
+- gTTS is now built as a wheel package (Python 2 & 3) (`#181 https://github.com/pndurette/gTTS/issues/181`_)
+
+
+Improved Documentation
+~~~~~~~~~~~~~~~~~~~~~~
+
+- Fixed bad example in docs (`#163 https://github.com/pndurette/gTTS/issues/163`_, `#166 https://github.com/pndurette/gTTS/issues/166`_)
+
+
+Misc
+~~~~
+
+- `#164 https://github.com/pndurette/gTTS/issues/164`_, `#171 https://github.com/pndurette/gTTS/issues/171`_, `#173 https://github.com/pndurette/gTTS/issues/173`_, `#185 https://github.com/pndurette/gTTS/issues/185`_
+
+
2.0.3 (2018-12-15)
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/MANIFEST.in new/gTTS-2.0.4/MANIFEST.in
--- old/gTTS-2.0.3/MANIFEST.in 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/MANIFEST.in 2019-08-30 02:57:17.000000000 +0200
@@ -1,4 +1,5 @@
include README.md
include CHANGELOG.rst
include CONTRIBUTING.rst
-include LICENSE
\ No newline at end of file
+include LICENSE
+include pytest.ini
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/PKG-INFO new/gTTS-2.0.4/PKG-INFO
--- old/gTTS-2.0.3/PKG-INFO 2018-12-15 08:01:37.000000000 +0100
+++ new/gTTS-2.0.4/PKG-INFO 2019-08-30 02:57:31.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: gTTS
-Version: 2.0.3
+Version: 2.0.4
Summary: gTTS (Google Text-to-Speech), a Python library and CLI tool to interface with Google Translate text-to-speech API
Home-page: https://github.com/pndurette/gTTS
Author: Pierre Nicolas Durette
@@ -53,18 +53,17 @@
[The MIT License (MIT)](LICENSE) Copyright © 2014-2018 Pierre Nicolas Durette
-Keywords: text to speech,Google Translate,TTS
+Keywords: gtts,text to speech,Google Translate,TTS
Platform: UNKNOWN
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: MacOS
Classifier: Operating System :: Unix
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
@@ -72,5 +71,5 @@
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >= 2.7
Description-Content-Type: text/markdown
-Provides-Extra: docs
Provides-Extra: tests
+Provides-Extra: docs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gTTS.egg-info/PKG-INFO new/gTTS-2.0.4/gTTS.egg-info/PKG-INFO
--- old/gTTS-2.0.3/gTTS.egg-info/PKG-INFO 2018-12-15 08:01:36.000000000 +0100
+++ new/gTTS-2.0.4/gTTS.egg-info/PKG-INFO 2019-08-30 02:57:31.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: gTTS
-Version: 2.0.3
+Version: 2.0.4
Summary: gTTS (Google Text-to-Speech), a Python library and CLI tool to interface with Google Translate text-to-speech API
Home-page: https://github.com/pndurette/gTTS
Author: Pierre Nicolas Durette
@@ -53,18 +53,17 @@
[The MIT License (MIT)](LICENSE) Copyright © 2014-2018 Pierre Nicolas Durette
-Keywords: text to speech,Google Translate,TTS
+Keywords: gtts,text to speech,Google Translate,TTS
Platform: UNKNOWN
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: MacOS
Classifier: Operating System :: Unix
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
@@ -72,5 +71,5 @@
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >= 2.7
Description-Content-Type: text/markdown
-Provides-Extra: docs
Provides-Extra: tests
+Provides-Extra: docs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gTTS.egg-info/SOURCES.txt new/gTTS-2.0.4/gTTS.egg-info/SOURCES.txt
--- old/gTTS-2.0.3/gTTS.egg-info/SOURCES.txt 2018-12-15 08:01:36.000000000 +0100
+++ new/gTTS-2.0.4/gTTS.egg-info/SOURCES.txt 2019-08-30 02:57:31.000000000 +0200
@@ -3,6 +3,7 @@
LICENSE
MANIFEST.in
README.md
+pytest.ini
setup.cfg
setup.py
gTTS.egg-info/PKG-INFO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gTTS.egg-info/requires.txt new/gTTS-2.0.4/gTTS.egg-info/requires.txt
--- old/gTTS-2.0.3/gTTS.egg-info/requires.txt 2018-12-15 08:01:36.000000000 +0100
+++ new/gTTS-2.0.4/gTTS.egg-info/requires.txt 2019-08-30 02:57:31.000000000 +0200
@@ -1,8 +1,8 @@
six
-bs4
+beautifulsoup4
click
requests
-gtts_token
+gtts_token>=1.1.3
[docs]
sphinx
@@ -12,9 +12,8 @@
towncrier
[tests]
-pytest
+pytest>=3.9
pytest-cov
-coveralls
flake8
testfixtures
mock
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/lang.py new/gTTS-2.0.4/gtts/lang.py
--- old/gTTS-2.0.3/gtts/lang.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/lang.py 2019-08-30 02:57:17.000000000 +0200
@@ -6,7 +6,7 @@
__all__ = ['tts_langs']
-URL_BASE = 'http://translate.google.com'
+URL_BASE = 'https://translate.google.com'
JS_FILE = 'translate_m.js'
# Logger
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/tests/test_cli.py new/gTTS-2.0.4/gtts/tests/test_cli.py
--- old/gTTS-2.0.3/gtts/tests/test_cli.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/tests/test_cli.py 2019-08-30 02:57:17.000000000 +0200
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
-import tempfile
-import unittest
-import six
+import pytest
+import re
import os
from click.testing import CliRunner
from gtts.cli import tts_cli
@@ -15,244 +14,242 @@
logger.handlers = []
-class TestParams(unittest.TestCase):
- """Test options and arguments"""
+"""Test options and arguments"""
- @classmethod
- def setUpClass(self):
- self.runner = CliRunner()
- (_, self.empty_file_path) = tempfile.mkstemp(suffix='.txt')
-
- def invoke(self, args, input=None):
- return self.runner.invoke(tts_cli, args, input)
-
- def invoke_debug(self, args, input=None):
- all_args = args + ['--debug']
- return self.invoke(all_args, input)
-
- # <text> tests
- def test_text_no_text_or_file(self):
- """One of <test> (arg) and <file> <opt> should be set"""
- result = self.invoke_debug([])
-
- self.assertIn("<file> required", result.output)
- self.assertNotEqual(result.exit_code, 0)
-
- def test_text_text_and_file(self):
- """<test> (arg) and <file> <opt> should not be set together"""
- result = self.invoke_debug(['--file', self.empty_file_path, 'test'])
-
- self.assertIn("<file> can't be used together", result.output)
- self.assertNotEqual(result.exit_code, 0)
-
- def test_text_empty(self):
- """Exit on no text to speak (via <file>)"""
- result = self.invoke_debug(['--file', self.empty_file_path])
-
- self.assertIn("No text to speak", result.output)
- self.assertNotEqual(result.exit_code, 0)
-
- # <file> tests
- def test_file_not_exists(self):
- """<file> should exist"""
- result = self.invoke_debug(['--file', 'notexist.txt', 'test'])
-
- self.assertIn("No such file or directory", result.output)
- self.assertNotEqual(result.exit_code, 0)
-
- # <all> tests
- def test_all(self):
- """Option <all> should return a list of languages"""
- result = self.invoke(['--all'])
-
- # One or more of " xy: name" (\n optional to match the last)
- # Ex. "<start> xx: xxxxx\n xx-yy: xxxxx\n xx: xxxxx<end>"
- # NB: assertRegex needs Py3.1+, use six
- six.assertRegex(
- self,
- result.output,
- r"^(?:\s{2}(\w{2}|\w{2}-\w{2}): .+\n?)+$")
- self.assertEqual(result.exit_code, 0)
-
- # <lang> tests
- def test_lang_not_valid(self):
- """Invalid <lang> should display an error"""
- result = self.invoke(['--lang', 'xx', 'test'])
-
- self.assertIn("xx' not in list of supported languages", result.output)
- self.assertNotEqual(result.exit_code, 0)
-
- def test_lang_nocheck(self):
- """Invalid <lang> (with <nocheck>) should display an error message from gtts"""
- with LogCapture() as lc:
- result = self.invoke_debug(
- ['--lang', 'xx', '--nocheck', 'test'])
-
- log = str(lc)
-
- self.assertIn('lang: xx', log)
- self.assertIn('lang_check: False', log)
- self.assertIn(
- "Probable cause: Unsupported language 'xx'",
- result.output)
- self.assertNotEqual(result.exit_code, 0)
-
- # Param set tests
- def test_params_set(self):
- """Options should set gTTS instance arguments (read from debug log)"""
- with LogCapture() as lc:
- result = self.invoke_debug(
- ['--lang', 'fr', '--slow', '--nocheck', 'test'])
-
- log = str(lc)
-
- self.assertIn('lang: fr', log)
- self.assertIn('lang_check: False', log)
- self.assertIn('slow: True', log)
- self.assertIn('text: test', log)
- self.assertEqual(result.exit_code, 0)
-
-
-class TestInputs(unittest.TestCase):
- """Test all input methods"""
-
- @classmethod
- def setUpClass(self):
- self.runner = CliRunner()
- def setUp(self):
- pwd = os.path.dirname(__file__)
+def runner(args, input=None):
+ return CliRunner().invoke(tts_cli, args, input)
- # Text for stdin ('-' for <text> or <file>)
- self.textstdin = """stdin
+
+def runner_debug(args, input=None):
+ return CliRunner().invoke(tts_cli, args + ['--debug'], input)
+
+
+# %% <text> tests
+def test_text_no_text_or_file():
+ """One of <test> (arg) and <file> <opt> should be set"""
+ result = runner_debug([])
+
+ assert "<file> required" in result.output
+ assert result.exit_code != 0
+
+
+def test_text_text_and_file(tmp_path):
+ """<test> (arg) and <file> <opt> should not be set together"""
+ filename = tmp_path / 'test_and_file.txt'
+ filename.touch()
+
+ result = runner_debug(['--file', str(filename), 'test'])
+
+ assert "<file> can't be used together" in result.output
+ assert result.exit_code != 0
+
+
+def test_text_empty(tmp_path):
+ """Exit on no text to speak (via <file>)"""
+ filename = tmp_path / 'text_empty.txt'
+ filename.touch()
+
+ result = runner_debug(['--file', str(filename)])
+
+ assert "No text to speak" in result.output
+ assert result.exit_code != 0
+
+# %% <file> tests
+
+
+def test_file_not_exists():
+ """<file> should exist"""
+ result = runner_debug(['--file', 'notexist.txt', 'test'])
+
+ assert "No such file or directory" in result.output
+ assert result.exit_code != 0
+
+# %% <all> tests
+
+
+def test_all():
+ """Option <all> should return a list of languages"""
+ result = runner(['--all'])
+
+ # One or more of " xy: name" (\n optional to match the last)
+ # Ex. "<start> xx: xxxxx\n xx-yy: xxxxx\n xx: xxxxx<end>"
+
+ assert re.match(r"^(?:\s{2}(\w{2}|\w{2}-\w{2}): .+\n?)+$", result.output)
+ assert result.exit_code == 0
+
+# %% <lang> tests
+
+
+def test_lang_not_valid():
+ """Invalid <lang> should display an error"""
+ result = runner(['--lang', 'xx', 'test'])
+
+ assert "xx' not in list of supported languages" in result.output
+ assert result.exit_code != 0
+
+
+def test_lang_nocheck():
+ """Invalid <lang> (with <nocheck>) should display an error message from gtts"""
+ with LogCapture() as lc:
+ result = runner_debug(['--lang', 'xx', '--nocheck', 'test'])
+
+ log = str(lc)
+
+ assert 'lang: xx' in log
+ assert 'lang_check: False' in log
+ assert "Probable cause: Unsupported language 'xx'" in result.output
+ assert result.exit_code != 0
+
+# %% Param set tests
+
+
+def test_params_set():
+ """Options should set gTTS instance arguments (read from debug log)"""
+ with LogCapture() as lc:
+ result = runner_debug(['--lang', 'fr', '--slow', '--nocheck', 'test'])
+
+ log = str(lc)
+
+ assert 'lang: fr' in log
+ assert 'lang_check: False' in log
+ assert 'slow: True' in log
+ assert 'text: test' in log
+ assert result.exit_code == 0
+
+
+# %% Test all input methods
+
+pwd = os.path.dirname(__file__)
+
+# Text for stdin ('-' for <text> or <file>)
+textstdin = """stdin
test
123"""
- # Text for stdin ('-' for <text> or <file>) (Unicode)
- self.textstdin_unicode = u"""你吃饭了吗?
+# Text for stdin ('-' for <text> or <file>) (Unicode)
+textstdin_unicode = u"""你吃饭了吗?
你最喜欢哪部电影?
我饿了,我要去做饭了。"""
- # Text for <text> and <file>
- self.text = """Can you make pink a little more pinkish can you make pink a little more pinkish, nor can you make the font bigger?
+# Text for <text> and <file>
+text = """Can you make pink a little more pinkish can you make pink a little more pinkish, nor can you make the font bigger?
How much will it cost the website doesn't have the theme i was going for."""
- self.textfile_ascii = os.path.join(
- pwd, 'input_files', 'test_cli_test_ascii.txt')
- # Text for <text> and <file> (Unicode)
- self.text_unicode = u"""这是一个三岁的小孩
+textfile_ascii = os.path.join(pwd, 'input_files', 'test_cli_test_ascii.txt')
+
+# Text for <text> and <file> (Unicode)
+text_unicode = u"""这是一个三岁的小孩
在讲述她从一系列照片里看到的东西。
对这个世界, 她也许还有很多要学的东西,
但在一个重要的任务上, 她已经是专家了:
去理解她所看到的东西。"""
- self.textfile_utf8 = os.path.join(
- pwd, 'input_files', 'test_cli_test_utf8.txt')
- def invoke(self, args, input=None):
- return self.runner.invoke(tts_cli, args, input)
+textfile_utf8 = os.path.join(pwd, 'input_files', 'test_cli_test_utf8.txt')
+
+"""
+Method that mimics's LogCapture's __str__ method to make
+the string in the comprehension a unicode literal for P2.7
+https://github.com/Simplistix/testfixtures/blob/32c87902cb111b7ede5a6abca9b5...
+"""
+
+
+def logcapture_str(lc):
+ if not lc.records:
+ return 'No logging captured'
+
+ return '\n'.join([u"%s %s\n %s" % r for r in lc.actual()])
+
+
+def test_stdin_text():
+ with LogCapture() as lc:
+ result = runner_debug(['-'], textstdin)
+ log = logcapture_str(lc)
+
+ assert 'text: %s' % textstdin in log
+ assert result.exit_code == 0
+
+
+def test_stdin_text_unicode():
+ with LogCapture() as lc:
+ result = runner_debug(['-'], textstdin_unicode)
+ log = logcapture_str(lc)
- def invoke_debug(self, args, input=None):
- all_args = args + ['--debug']
- return self.invoke(all_args, input)
+ assert u'text: %s' % textstdin_unicode in log
+ assert result.exit_code == 0
- # Method that mimics's LogCapture's __str__ method to make
- # the string in the comprehension a unicode literal for P2.7
- # https://github.com/Simplistix/testfixtures/blob/32c87902cb111b7ede5a6abca9b5...
- def logcapture_str(self, lc):
- if not lc.records:
- return 'No logging captured'
- return '\n'.join([u"%s %s\n %s" % r for r in lc.actual()])
- def test_stdin_text(self):
- with LogCapture() as lc:
- result = self.invoke_debug(['-'], self.textstdin)
- log = self.logcapture_str(lc)
+def test_stdin_file():
+ with LogCapture() as lc:
+ result = runner_debug(['--file', '-'], textstdin)
+ log = logcapture_str(lc)
- self.assertIn('text: %s' % self.textstdin, log)
- self.assertEqual(result.exit_code, 0)
+ assert 'text: %s' % textstdin in log
+ assert result.exit_code == 0
- def test_stdin_text_unicode(self):
- with LogCapture() as lc:
- result = self.invoke_debug(['-'], self.textstdin_unicode)
- log = self.logcapture_str(lc)
- self.assertIn(u'text: %s' % self.textstdin_unicode, log)
- self.assertEqual(result.exit_code, 0)
+def test_stdin_file_unicode():
+ with LogCapture() as lc:
+ result = runner_debug(['--file', '-'], textstdin_unicode)
+ log = logcapture_str(lc)
- def test_stdin_file(self):
- with LogCapture() as lc:
- result = self.invoke_debug(['--file', '-'], self.textstdin)
- log = self.logcapture_str(lc)
+ assert 'text: %s' % textstdin_unicode in log
+ assert result.exit_code == 0
- self.assertIn('text: %s' % self.textstdin, log)
- self.assertEqual(result.exit_code, 0)
- def test_stdin_file_unicode(self):
- with LogCapture() as lc:
- result = self.invoke_debug(['--file', '-'], self.textstdin_unicode)
- log = self.logcapture_str(lc)
+def test_text():
+ with LogCapture() as lc:
+ result = runner_debug([text])
+ log = logcapture_str(lc)
- self.assertIn('text: %s' % self.textstdin_unicode, log)
- self.assertEqual(result.exit_code, 0)
+ assert "text: %s" % text in log
+ assert result.exit_code == 0
- def test_text(self):
- with LogCapture() as lc:
- result = self.invoke_debug([self.text])
- log = self.logcapture_str(lc)
- self.assertIn("text: %s" % self.text, log)
- self.assertEqual(result.exit_code, 0)
+def test_text_unicode():
+ with LogCapture() as lc:
+ result = runner_debug([text_unicode])
+ log = logcapture_str(lc)
- def test_text_unicode(self):
- with LogCapture() as lc:
- result = self.invoke_debug([self.text_unicode])
- log = self.logcapture_str(lc)
+ assert "text: %s" % text_unicode in log
+ assert result.exit_code == 0
- self.assertIn("text: %s" % self.text_unicode, log)
- self.assertEqual(result.exit_code, 0)
- def test_file_ascii(self):
- with LogCapture() as lc:
- result = self.invoke_debug(['--file', self.textfile_ascii])
- log = self.logcapture_str(lc)
+def test_file_ascii():
+ with LogCapture() as lc:
+ result = runner_debug(['--file', textfile_ascii])
+ log = logcapture_str(lc)
- self.assertIn("text: %s" % self.text, log)
- self.assertEqual(result.exit_code, 0)
+ assert "text: %s" % text in log
+ assert result.exit_code == 0
- def test_file_utf8(self):
- with LogCapture() as lc:
- result = self.invoke_debug(['--file', self.textfile_utf8])
- log = self.logcapture_str(lc)
- self.assertIn("text: %s" % self.text_unicode, log)
- self.assertEqual(result.exit_code, 0)
+def test_file_utf8():
+ with LogCapture() as lc:
+ result = runner_debug(['--file', textfile_utf8])
+ log = logcapture_str(lc)
+ assert "text: %s" % text_unicode in log
+ assert result.exit_code == 0
-class TestOutputs(unittest.TestCase):
- """Test all ouput methods"""
- @classmethod
- def setUp(self):
- self.runner = CliRunner()
- (_, self.save_file_path) = tempfile.mkstemp(suffix='.mp3')
+def test_stdout():
+ result = runner(['test'])
- def invoke(self, args, input=None):
- return self.runner.invoke(tts_cli, args, input)
+ # The MP3 encoding (LAME 3.99.5) leaves a signature in the raw output
+ assert 'LAME3.99.5' in result.output
+ assert result.exit_code == 0
- def test_stdout(self):
- result = self.invoke(['test'])
- # The MP3 encoding (LAME 3.99.5) leaves a signature in the raw output
- self.assertIn('LAME3.99.5', result.output)
- self.assertEqual(result.exit_code, 0)
+def test_file(tmp_path):
+ filename = tmp_path / 'out.mp3'
- def test_file(self):
- result = self.invoke(['test', '--output', self.save_file_path])
+ result = runner(['test', '--output', str(filename)])
- # Check if files created is > 2k
- self.assertTrue(os.path.getsize(self.save_file_path) > 2000)
- self.assertEqual(result.exit_code, 0)
+ # Check if files created is > 2k
+ assert filename.stat().st_size > 2000
+ assert result.exit_code == 0
if __name__ == '__main__':
- unittest.main()
+ pytest.main(['-x', __file__])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/tests/test_lang.py new/gTTS-2.0.4/gtts/tests/test_lang.py
--- old/gTTS-2.0.3/gtts/tests/test_lang.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/tests/test_lang.py 2019-08-30 02:57:17.000000000 +0200
@@ -1,38 +1,36 @@
# -*- coding: utf-8 -*-
-import unittest
+import pytest
from mock import patch
from gtts.lang import tts_langs, _fetch_langs, _extra_langs
-class TestLanguages(unittest.TestCase):
- """Test language list downloading"""
+"""Test language list downloading"""
- def test_fetch_langs(self):
- """Fetch languages successfully"""
- # Downloaded Languages
- # Safe to assume 'en' (english) will always be there
- scraped_langs = _fetch_langs()
- self.assertTrue('en' in scraped_langs)
-
- # Scraping garbage
- self.assertFalse('Detect language' in scraped_langs)
- self.assertFalse('—' in scraped_langs)
-
- # Add-in Languages
- all_langs = tts_langs()
- extra_langs = _extra_langs()
- self.assertEqual(
- len(all_langs),
- len(scraped_langs) +
- len(extra_langs))
-
- @patch("gtts.lang.URL_BASE", "http://abc.def.hij.dghj")
- def test_fetch_langs_exception(self):
- """Raise RuntimeError on language fetch exception"""
- with self.assertRaises(RuntimeError):
- tts_langs()
+
+def test_fetch_langs():
+ """Fetch languages successfully"""
+ # Downloaded Languages
+ # Safe to assume 'en' (english) will always be there
+ scraped_langs = _fetch_langs()
+ assert 'en' in scraped_langs
+
+ # Scraping garbage
+ assert 'Detect language' not in scraped_langs
+ assert '—' not in scraped_langs
+
+ # Add-in Languages
+ all_langs = tts_langs()
+ extra_langs = _extra_langs()
+ assert len(all_langs) == len(scraped_langs) + len(extra_langs)
+
+
+@patch("gtts.lang.URL_BASE", "http://abc.def.hij.dghj")
+def test_fetch_langs_exception():
+ """Raise RuntimeError on language fetch exception"""
+ with pytest.raises(RuntimeError):
+ tts_langs()
if __name__ == '__main__':
- unittest.main()
+ pytest.main(['-x', __file__])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/tests/test_tts.py new/gTTS-2.0.4/gtts/tests/test_tts.py
--- old/gTTS-2.0.3/gtts/tests/test_tts.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/tests/test_tts.py 2019-08-30 02:57:17.000000000 +0200
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
import os
-import tempfile
-import unittest
+import pytest
from mock import Mock
from gtts.tts import gTTS, gTTSError
@@ -14,171 +13,144 @@
# * 'all': All of the above
# * <csv>: Languages tags list to test
# Unset TEST_LANGS to test everything ('all')
-# See: test_langs_dict()
+# See: langs_dict()
-class TestTTS(unittest.TestCase):
+"""Construct a dict of suites of languages to test.
+{ '<suite name>' : <list or dict of language tags> }
+
+ex.: { 'fetch' : {'en': 'English', 'fr': 'French'},
+ 'extra' : {'en': 'English', 'fr': 'French'} }
+ex.: { 'environ' : ['en', 'fr'] }
+"""
+env = os.environ.get('TEST_LANGS')
+if not env or env == 'all':
+ langs = _fetch_langs()
+ langs.update(_extra_langs())
+elif env == 'fetch':
+ langs = _fetch_langs()
+elif env == 'extra':
+ langs = _extra_langs()
+else:
+ env_langs = {l: l for l in env.split(',') if l}
+ langs = env_langs
+
+
+@pytest.mark.parametrize('lang', langs.keys(), ids=list(langs.values()))
+def test_TTS(tmp_path, lang):
"""Test all supported languages and file save"""
- def setUp(self):
- self.text = "This is a test"
+ text = "This is a test"
+ """Create output .mp3 file successfully"""
+ for slow in (False, True):
+ filename = tmp_path / 'test_{}_.mp3'.format(lang)
+ # Create gTTS and save
+ tts = gTTS(text, lang, slow=slow)
+ tts.save(filename)
- def check_tts(self, lang):
- """Create output .mp3 file successfully"""
- for slow in (False, True):
- with tempfile.SpooledTemporaryFile(suffix='.mp3', prefix='test_{}_'.format(lang)) as f:
- # Create gTTS and save
- tts = gTTS(self.text, lang, slow=slow)
- tts.write_to_fp(f)
-
- # Check if files created is > 2k
- self.assertTrue(os.fstat(f.fileno()).st_size > 2000)
-
-
-def test_langs_dict():
- """Construct a dict of suites of languages to test.
- { '<suite name>' : <list or dict of language tags> }
-
- ex.: { 'fetch' : {'en': 'English', 'fr': 'French'},
- 'extra' : {'en': 'English', 'fr': 'French'} }
- ex.: { 'environ' : ['en', 'fr'] }
- """
- langs = dict()
- env = os.environ.get('TEST_LANGS', '')
- if env == '' or env == 'all':
- langs['fetch'] = _fetch_langs()
- langs['extra'] = _extra_langs()
- elif env == 'fetch':
- langs['fetch'] = _fetch_langs()
- elif env == 'extra':
- langs['extra'] = _extra_langs()
- else:
- env_langs = env.split(',')
- env_langs = [l for l in env_langs if l]
- langs['environ'] = env_langs
- return langs
-
-
-# Generate TestTTS.check_tts tests for each language
-# Based on: http://stackoverflow.com/a/1194012
-for suite, langs in test_langs_dict().items():
- for l in langs:
- def ch(l):
- return lambda self: self.check_tts(l)
- setattr(TestTTS, "test_tts_%s_%s" % (suite, l), ch(l))
-
-
-class TestInit(unittest.TestCase):
- """Test gTTS init"""
-
- def test_unsupported_language_check(self):
- """Raise ValueError on unsupported language (with language check)"""
- lang = 'xx'
- text = "Lorem ipsum"
- check = True
- with self.assertRaises(ValueError):
- gTTS(text=text, lang=lang, lang_check=check)
-
- def test_empty_string(self):
- """Raise AssertionError on empty string"""
- text = ""
- with self.assertRaises(AssertionError):
- gTTS(text=text)
-
- def test_no_text_parts(self):
- """Raises AssertionError on no content to send to API (no text_parts)"""
- text = " ..,\n"
- with self.assertRaises(AssertionError):
- with tempfile.SpooledTemporaryFile() as f:
- tts = gTTS(text=text)
- tts.write_to_fp(f)
+ # Check if files created is > 2k
+ assert filename.stat().st_size > 2000
-class TestWrite(unittest.TestCase):
- """Test write_to_fp()/save() cases not covered elsewhere in this file"""
+def test_unsupported_language_check():
+ """Raise ValueError on unsupported language (with language check)"""
+ lang = 'xx'
+ text = "Lorem ipsum"
+ check = True
+ with pytest.raises(ValueError):
+ gTTS(text=text, lang=lang, lang_check=check)
- def test_bad_fp_type(self):
- """Raise TypeError if fp is not a file-like object (no .write())"""
- # Create gTTS and save
- tts = gTTS(text='test')
- with self.assertRaises(TypeError):
- tts.write_to_fp(5)
-
- def test_save(self):
- """Save .mp3 file successfully"""
- (_, save_file_path) = tempfile.mkstemp(suffix='.mp3')
- # Create gTTS and save
- tts = gTTS(text='test')
- tts.save(save_file_path)
+def test_empty_string():
+ """Raise AssertionError on empty string"""
+ text = ""
+ with pytest.raises(AssertionError):
+ gTTS(text=text)
+
+
+def test_no_text_parts(tmp_path):
+ """Raises AssertionError on no content to send to API (no text_parts)"""
+ text = " ..,\n"
+ with pytest.raises(AssertionError):
+ filename = tmp_path / 'no_content.txt'
+ tts = gTTS(text=text)
+ tts.save(filename)
+
+
+# %%Test write_to_fp()/save() cases not covered elsewhere in this file
+
+def test_bad_fp_type():
+ """Raise TypeError if fp is not a file-like object (no .write())"""
+ # Create gTTS and save
+ tts = gTTS(text='test')
+ with pytest.raises(TypeError):
+ tts.write_to_fp(5)
+
+
+def test_save(tmp_path):
+ """Save .mp3 file successfully"""
+ filename = tmp_path / 'save.mp3'
+ # Create gTTS and save
+ tts = gTTS(text='test')
+ tts.save(filename)
+
+ # Check if file created is > 2k
+ assert filename.stat().st_size > 2000
+
+
+def test_msg():
+ """Test gTTsError internal exception handling
+ Set exception message successfully"""
+ error1 = gTTSError('test')
+ assert 'test' == error1.msg
+
+ error2 = gTTSError()
+ assert error2.msg is None
+
+
+def test_infer_msg():
+ """Infer message sucessfully based on context"""
+
+ # 403
+ tts403 = Mock()
+ response403 = Mock(status_code=403, reason='aaa')
+ error403 = gTTSError(tts=tts403, response=response403)
+ assert error403.msg == "403 (aaa) from TTS API. Probable cause: Bad token or upstream API changes"
- # Check if file created is > 2k
- self.assertTrue(os.stat(save_file_path).st_size > 2000)
+ # 404 (and not lang_check)
+ tts404 = Mock(lang='xx', lang_check=False)
+ response404 = Mock(status_code=404, reason='bbb')
+ error404 = gTTSError(tts=tts404, response=response404)
+ assert error404.msg == "404 (bbb) from TTS API. Probable cause: Unsupported language 'xx'"
+ # >= 500
+ tts500 = Mock()
+ response500 = Mock(status_code=500, reason='ccc')
+ error500 = gTTSError(tts=tts500, response=response500)
+ assert error500.msg == "500 (ccc) from TTS API. Probable cause: Uptream API error. Try again later."
-class TestgTTSError(unittest.TestCase):
- """Test gTTsError internal exception handling"""
-
- def test_msg(self):
- """Set exception message successfully"""
- error1 = gTTSError('test')
- self.assertEqual('test', error1.msg)
-
- error2 = gTTSError()
- self.assertIsNone(error2.msg)
-
- def test_infer_msg(self):
- """Infer message sucessfully based on context"""
-
- # 403
- tts403 = Mock()
- response403 = Mock(status_code=403, reason='aaa')
- error403 = gTTSError(tts=tts403, response=response403)
- self.assertEqual(
- error403.msg,
- "403 (aaa) from TTS API. Probable cause: Bad token or upstream API changes")
-
- # 404 (and not lang_check)
- tts404 = Mock(lang='xx', lang_check=False)
- response404 = Mock(status_code=404, reason='bbb')
- error404 = gTTSError(tts=tts404, response=response404)
- self.assertEqual(
- error404.msg,
- "404 (bbb) from TTS API. Probable cause: Unsupported language 'xx'")
-
- # >= 500
- tts500 = Mock()
- response500 = Mock(status_code=500, reason='ccc')
- error500 = gTTSError(tts=tts500, response=response500)
- self.assertEqual(
- error500.msg,
- "500 (ccc) from TTS API. Probable cause: Uptream API error. Try again later.")
-
- # Unknown (ex. 100)
- tts100 = Mock()
- response100 = Mock(status_code=100, reason='ddd')
- error100 = gTTSError(tts=tts100, response=response100)
- self.assertEqual(
- error100.msg,
- "100 (ddd) from TTS API. Probable cause: Unknown")
+ # Unknown (ex. 100)
+ tts100 = Mock()
+ response100 = Mock(status_code=100, reason='ddd')
+ error100 = gTTSError(tts=tts100, response=response100)
+ assert error100.msg == "100 (ddd) from TTS API. Probable cause: Unknown"
-class TestWebRequest(unittest.TestCase):
+def test_WebRequest(tmp_path):
"""Test Web Requests"""
- def setUp(self):
- self.text = "Lorem ipsum"
+ text = "Lorem ipsum"
- def test_unsupported_language_no_check(self):
- """Raise gTTSError on unsupported language (without language check)"""
- lang = 'xx'
- check = False
- with self.assertRaises(gTTSError):
- with tempfile.SpooledTemporaryFile() as f:
- # Create gTTS
- tts = gTTS(text=self.text, lang=lang, lang_check=check)
- tts.write_to_fp(f)
+ """Raise gTTSError on unsupported language (without language check)"""
+ lang = 'xx'
+ check = False
+
+ with pytest.raises(gTTSError):
+ filename = tmp_path / 'xx.txt'
+ # Create gTTS
+ tts = gTTS(text=text, lang=lang, lang_check=check)
+ tts.save(filename)
if __name__ == '__main__':
- unittest.main()
+ pytest.main(['-x', __file__])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/tests/test_utils.py new/gTTS-2.0.4/gtts/tests/test_utils.py
--- old/gTTS-2.0.3/gtts/tests/test_utils.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/tests/test_utils.py 2019-08-30 02:57:17.000000000 +0200
@@ -1,55 +1,56 @@
# -*- coding: utf-8 -*-
-import unittest
+import pytest
from gtts.utils import _minimize, _len, _clean_tokens
+delim = ' '
+Lmax = 10
-class TestMinimize(unittest.TestCase):
- def setUp(self):
- self.delim = ' '
- self.max = 10
-
- def test_ascii(self):
- _in = "Bacon ipsum dolor sit amet"
- _out = ["Bacon", "ipsum", "dolor sit", "amet"]
- self.assertEqual(_minimize(_in, self.delim, self.max), _out)
-
- def test_ascii_no_delim(self):
- _in = "Baconipsumdolorsitametflankcornedbee"
- _out = ["Baconipsum", "dolorsitam", "etflankcor", "nedbee"]
- self.assertEqual(_minimize(_in, self.delim, self.max), _out)
-
- def test_unicode(self):
- _in = u"这是一个三岁的小孩在讲述他从一系列照片里看到的东西。"
- _out = [u"这是一个三岁的小孩在", u"讲述他从一系列照片里", u"看到的东西。"]
- self.assertEqual(_minimize(_in, self.delim, self.max), _out)
-
- def test_startwith_delim(self):
- _in = self.delim + "test"
- _out = ["test"]
- self.assertEqual(_minimize(_in, self.delim, self.max), _out)
-
-
-class TestLen(unittest.TestCase):
- def test_ascii(self):
- text = "Bacon ipsum dolor sit amet flank corned beef."
- self.assertEqual(_len(text), 45)
-
- def test_unicode(self):
- text = u"但在一个重要的任务上"
- self.assertEqual(_len(text), 10)
-
-
-class TestCleanToken(unittest.TestCase):
- def test_only_space_and_punc(self):
- _in = [",(:)?", "\t ", "\n"]
- _out = []
- self.assertEqual(_clean_tokens(_in), _out)
-
- def test_strip(self):
- _in = [" Bacon ", "& ", "ipsum\r", "."]
- _out = ["Bacon", "&", "ipsum"]
- self.assertEqual(_clean_tokens(_in), _out)
+
+def test_ascii():
+ _in = "Bacon ipsum dolor sit amet"
+ _out = ["Bacon", "ipsum", "dolor sit", "amet"]
+ assert _minimize(_in, delim, Lmax) == _out
+
+
+def test_ascii_no_delim():
+ _in = "Baconipsumdolorsitametflankcornedbee"
+ _out = ["Baconipsum", "dolorsitam", "etflankcor", "nedbee"]
+ assert _minimize(_in, delim, Lmax) == _out
+
+
+def test_unicode():
+ _in = u"这是一个三岁的小孩在讲述他从一系列照片里看到的东西。"
+ _out = [u"这是一个三岁的小孩在", u"讲述他从一系列照片里", u"看到的东西。"]
+ assert _minimize(_in, delim, Lmax) == _out
+
+
+def test_startwith_delim():
+ _in = delim + "test"
+ _out = ["test"]
+ assert _minimize(_in, delim, Lmax) == _out
+
+
+def test_len_ascii():
+ text = "Bacon ipsum dolor sit amet flank corned beef."
+ assert _len(text) == 45
+
+
+def test_len_unicode():
+ text = u"但在一个重要的任务上"
+ assert _len(text) == 10
+
+
+def test_only_space_and_punc():
+ _in = [",(:)?", "\t ", "\n"]
+ _out = []
+ assert _clean_tokens(_in) == _out
+
+
+def test_strip():
+ _in = [" Bacon ", "& ", "ipsum\r", "."]
+ _out = ["Bacon", "&", "ipsum"]
+ assert _clean_tokens(_in) == _out
if __name__ == '__main__':
- unittest.main()
+ pytest.main(['-x', __file__])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/tts.py new/gTTS-2.0.4/gtts/tts.py
--- old/gTTS-2.0.3/gtts/tts.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/tts.py 2019-08-30 02:57:17.000000000 +0200
@@ -245,7 +245,7 @@
:class:`gTTSError`: When there's an error with the API request.
"""
- with open(savefile, 'wb') as f:
+ with open(str(savefile), 'wb') as f:
self.write_to_fp(f)
log.debug("Saved to %s", savefile)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/gtts/version.py new/gTTS-2.0.4/gtts/version.py
--- old/gTTS-2.0.3/gtts/version.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/gtts/version.py 2019-08-30 02:57:17.000000000 +0200
@@ -1 +1 @@
-__version__ = '2.0.3'
+__version__ = '2.0.4'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/pytest.ini new/gTTS-2.0.4/pytest.ini
--- old/gTTS-2.0.3/pytest.ini 1970-01-01 01:00:00.000000000 +0100
+++ new/gTTS-2.0.4/pytest.ini 2019-08-30 02:57:17.000000000 +0200
@@ -0,0 +1,2 @@
+[pytest]
+minversion = 3.9
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/setup.cfg new/gTTS-2.0.4/setup.cfg
--- old/gTTS-2.0.3/setup.cfg 2018-12-15 08:01:37.000000000 +0100
+++ new/gTTS-2.0.4/setup.cfg 2019-08-30 02:57:31.000000000 +0200
@@ -6,6 +6,7 @@
url = https://github.com/pndurette/gTTS
license = MIT
keywords =
+ gtts
text to speech
Google Translate
TTS
@@ -13,13 +14,12 @@
Environment :: Console
Intended Audience :: Developers
License :: OSI Approved :: MIT License
- Operating System :: MacOS :: MacOS X
+ Operating System :: MacOS
Operating System :: Unix
Operating System :: POSIX
Operating System :: POSIX :: Linux
Operating System :: Microsoft :: Windows
Programming Language :: Python :: 2.7
- Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
@@ -39,16 +39,15 @@
packages = find:
install_requires =
six
- bs4
+ beautifulsoup4
click
requests
- gtts_token
+ gtts_token >= 1.1.3
[options.extras_require]
tests =
- pytest
+ pytest >= 3.9
pytest-cov
- coveralls
flake8
testfixtures
mock
@@ -71,7 +70,6 @@
[coverage:run]
cover_pylib = false
omit =
- /home/travis/virtualenv/*
*/site-packages/*
gtts/tests/*
gtts/tokenizer/tests/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gTTS-2.0.3/setup.py new/gTTS-2.0.4/setup.py
--- old/gTTS-2.0.3/setup.py 2018-12-15 08:00:34.000000000 +0100
+++ new/gTTS-2.0.4/setup.py 2019-08-30 02:57:17.000000000 +0200
@@ -4,6 +4,6 @@
exec(open('gtts/version.py').read())
setup(
- version=__version__, # noqa: F821
+ version=__version__, # type: ignore # noqa: F821
test_suite='gtts.tests',
)
++++++ remove-pip-requirement.patch ++++++
--- /var/tmp/diff_new_pack.7nyYFe/_old 2019-09-27 14:47:06.124974821 +0200
+++ /var/tmp/diff_new_pack.7nyYFe/_new 2019-09-27 14:47:06.124974821 +0200
@@ -1,8 +1,8 @@
-Index: gTTS-2.0.3/setup.cfg
+Index: gTTS-2.0.4/setup.cfg
===================================================================
---- gTTS-2.0.3.orig/setup.cfg
-+++ gTTS-2.0.3/setup.cfg
-@@ -33,13 +33,11 @@ long_description_content_type = text/mar
+--- gTTS-2.0.4.orig/setup.cfg
++++ gTTS-2.0.4/setup.cfg
+@@ -33,8 +33,6 @@ long_description_content_type = text/mar
python_requires = >= 2.7
setup_requires =
setuptools >= 38.6
@@ -11,9 +11,3 @@
include_package_data = True
packages = find:
install_requires =
- six
-- bs4
-+ beautifulsoup4
- click
- requests
- gtts_token