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 <[email protected]> + +- 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/32c87902cb111b7ede5a6abca9b597db551c88ef/testfixtures/logcapture.py#L149 +""" + + +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/32c87902cb111b7ede5a6abca9b597db551c88ef/testfixtures/logcapture.py#L149 - 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 + + [email protected]('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
