diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..f394c174 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,68 @@ +name: CI + +on: + [push, pull_request] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + python-version: ["3.11", "3.12", "3.13"] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install system dependencies (Ubuntu) + if: runner.os == 'Linux' + run: | + bash install_dependencies.sh + + - name: Install system dependencies (Windows) + if: runner.os == 'Windows' + run: | + # Install chocolatey packages if needed + # choco install espeak --yes + # For now, we'll use conda-forge for cross-platform audio packages + echo "Windows system dependencies would be installed here" + + - name: Cache pip dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + %APPDATA%\pip\Cache + key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements*.txt', '**/pyproject.toml', '**/setup.py') }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.python-version }}- + ${{ runner.os }}-pip- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build setuptools wheel + + - name: Build package + run: | + python -m build + + - name: Install package + shell: bash + run: | + # Install the built package + pip install dist/*.whl + + - name: Run tests with pytest + run: | + pip install pytest + pip install -r requirements_dev.txt + pytest aeneas/tests + diff --git a/aeneas/cdtw/cdtw_setup.py b/aeneas/cdtw/cdtw_setup.py index 0bf72553..257e76a7 100644 --- a/aeneas/cdtw/cdtw_setup.py +++ b/aeneas/cdtw/cdtw_setup.py @@ -30,7 +30,6 @@ from __future__ import absolute_import from __future__ import print_function from numpy import get_include -from numpy.distutils import misc_util from setuptools import Extension from setuptools import setup import sys @@ -52,7 +51,7 @@ version="1.7.4", description="Python C Extension for computing the DTW as fast as your bare metal allows.", ext_modules=[CMODULE], - include_dirs=misc_util.get_numpy_include_dirs() + include_dirs=[get_include()] ) print("\n[INFO] Module cdtw successfully compiled\n") diff --git a/aeneas/cmfcc/cmfcc_setup.py b/aeneas/cmfcc/cmfcc_setup.py index ae48beb1..53e465df 100644 --- a/aeneas/cmfcc/cmfcc_setup.py +++ b/aeneas/cmfcc/cmfcc_setup.py @@ -30,7 +30,6 @@ from __future__ import absolute_import from __future__ import print_function from numpy import get_include -from numpy.distutils import misc_util from setuptools import Extension from setuptools import setup import sys @@ -53,7 +52,7 @@ version="1.7.4", description="Python C Extension for computing the MFCCs as fast as your bare metal allows.", ext_modules=[CMODULE], - include_dirs=misc_util.get_numpy_include_dirs() + include_dirs=[get_include()] ) print("\n[INFO] Module cmfcc successfully compiled\n") diff --git a/aeneas/cwave/cwave_setup.py b/aeneas/cwave/cwave_setup.py index da548974..006b6fa6 100644 --- a/aeneas/cwave/cwave_setup.py +++ b/aeneas/cwave/cwave_setup.py @@ -30,7 +30,6 @@ from __future__ import absolute_import from __future__ import print_function from numpy import get_include -from numpy.distutils import misc_util from setuptools import Extension from setuptools import setup import sys @@ -52,7 +51,7 @@ version="1.7.4", description="Python C Extension for for reading WAVE files.", ext_modules=[CMODULE], - include_dirs=misc_util.get_numpy_include_dirs() + include_dirs=[get_include()] ) print("\n[INFO] Module cwave successfully compiled\n") diff --git a/aeneas/tests/test_textfile.py b/aeneas/tests/test_textfile.py index a498fb91..f7986695 100644 --- a/aeneas/tests/test_textfile.py +++ b/aeneas/tests/test_textfile.py @@ -506,13 +506,13 @@ def test_filter_ignore_regex_strip(self): self.filter_ignore_regex("word", [u"word abc word"], [u"abc"]) def test_filter_ignore_regex_parenthesis(self): - self.filter_ignore_regex("\(.*?\)", [u"(CHAR) bla bla bla"], [u"bla bla bla"]) + self.filter_ignore_regex(r"\(.*?\)", [u"(CHAR) bla bla bla"], [u"bla bla bla"]) def test_filter_ignore_regex_brackets(self): - self.filter_ignore_regex("\[.*?\]", [u"[CHAR] bla bla bla"], [u"bla bla bla"]) + self.filter_ignore_regex(r"\[.*?\]", [u"[CHAR] bla bla bla"], [u"bla bla bla"]) def test_filter_ignore_regex_braces(self): - self.filter_ignore_regex("\{.*?\}", [u"{CHAR} bla bla bla"], [u"bla bla bla"]) + self.filter_ignore_regex(r"\{.*?\}", [u"{CHAR} bla bla bla"], [u"bla bla bla"]) def test_filter_ignore_regex_entire_match(self): self.filter_ignore_regex("word", [u"word"], [u""]) diff --git a/aeneas/textfile.py b/aeneas/textfile.py index bb888ea7..f9975ff4 100644 --- a/aeneas/textfile.py +++ b/aeneas/textfile.py @@ -780,7 +780,7 @@ def nodes_at_level(root, level): indent = u" " * 2 * (level - 1) self.log([u"%sRegex for %s: '%s'", indent, attribute_name, regex_string]) regex = re.compile(r".*\b" + regex_string + r"\b.*") - return root.findAll(attrs={attribute_name: regex}) + return root.find_all(attrs={attribute_name: regex}) # # TODO better and/or parametric parsing, # for example, removing tags but keeping text, etc. @@ -953,7 +953,7 @@ def filter_attributes(): ids = [] filter_attributes = filter_attributes() self.log([u"Finding elements matching attributes '%s'", filter_attributes]) - nodes = soup.findAll(attrs=filter_attributes) + nodes = soup.find_all(attrs=filter_attributes) for node in nodes: try: f_id = gf.safe_unicode(node["id"]) diff --git a/aeneas/tools/bin/__init__.py b/aeneas/tools/bin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bin/aeneas_check_setup.py b/aeneas/tools/bin/aeneas_check_setup.py similarity index 100% rename from bin/aeneas_check_setup.py rename to aeneas/tools/bin/aeneas_check_setup.py diff --git a/bin/aeneas_convert_syncmap.py b/aeneas/tools/bin/aeneas_convert_syncmap.py similarity index 100% rename from bin/aeneas_convert_syncmap.py rename to aeneas/tools/bin/aeneas_convert_syncmap.py diff --git a/bin/aeneas_download.py b/aeneas/tools/bin/aeneas_download.py similarity index 100% rename from bin/aeneas_download.py rename to aeneas/tools/bin/aeneas_download.py diff --git a/bin/aeneas_execute_job.py b/aeneas/tools/bin/aeneas_execute_job.py similarity index 100% rename from bin/aeneas_execute_job.py rename to aeneas/tools/bin/aeneas_execute_job.py diff --git a/bin/aeneas_execute_task.py b/aeneas/tools/bin/aeneas_execute_task.py similarity index 100% rename from bin/aeneas_execute_task.py rename to aeneas/tools/bin/aeneas_execute_task.py diff --git a/bin/aeneas_plot_waveform.py b/aeneas/tools/bin/aeneas_plot_waveform.py similarity index 100% rename from bin/aeneas_plot_waveform.py rename to aeneas/tools/bin/aeneas_plot_waveform.py diff --git a/bin/aeneas_synthesize_text.py b/aeneas/tools/bin/aeneas_synthesize_text.py similarity index 100% rename from bin/aeneas_synthesize_text.py rename to aeneas/tools/bin/aeneas_synthesize_text.py diff --git a/bin/aeneas_validate.py b/aeneas/tools/bin/aeneas_validate.py similarity index 100% rename from bin/aeneas_validate.py rename to aeneas/tools/bin/aeneas_validate.py diff --git a/aeneas/wavfile.py b/aeneas/wavfile.py index 5d571b52..229a1076 100644 --- a/aeneas/wavfile.py +++ b/aeneas/wavfile.py @@ -75,7 +75,7 @@ def _read_data_chunk(fid, comp, noc, bits, mmap=False): else: dtype += 'f%d' % bytes if not mmap: - data = numpy.fromstring(fid.read(size), dtype=dtype) + data = numpy.frombuffer(fid.read(size), dtype=dtype) else: start = fid.tell() data = numpy.memmap(fid, dtype=dtype, mode='c', offset=start, diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..5f8a09ca --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,160 @@ +[build-system] +requires = ["setuptools", "wheel", "numpy"] +build-backend = "setuptools.build_meta" + +[project] +name = "aeneas" +version = "1.7.4.0" +description = "aeneas is a Python/C library and a set of tools to automagically synchronize audio and text (aka forced alignment)" +readme = "README.rst" +authors = [ + { name = "Alberto Pettarin", email = "alberto@albertopettarin.it" } +] +license = "AGPL-3.0-only" +keywords = [ + "AUD", + "AWS Polly TTS API", + "CSV", + "DTW", + "EAF", + "ELAN", + "EPUB 3 Media Overlay", + "EPUB 3", + "EPUB", + "Festival", + "JSON", + "MFCC", + "Mel-frequency cepstral coefficients", + "Nuance TTS API", + "ReadBeyond Sync", + "ReadBeyond", + "SBV", + "SMIL", + "SRT", + "SSV", + "SUB", + "TGT", + "TSV", + "TTML", + "TTS", + "TextGrid", + "VTT", + "XML", + "aeneas", + "audio/text alignment", + "dynamic time warping", + "eSpeak", + "eSpeak-ng", + "espeak", + "espeak-ng", + "festival", + "ffmpeg", + "ffprobe", + "forced alignment", + "media overlay", + "rb_smil_emulator", + "speech to text", + "subtitles", + "sync", + "synchronization", + "text to speech", + "text2wave", + "tts", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: End Users/Desktop", + "Intended Audience :: Science/Research", + "Natural Language :: English", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: C", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Topic :: Education", + "Topic :: Multimedia", + "Topic :: Multimedia :: Sound/Audio", + "Topic :: Multimedia :: Sound/Audio :: Analysis", + "Topic :: Multimedia :: Sound/Audio :: Speech", + "Topic :: Printing", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Mathematics", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Text Processing", + "Topic :: Text Processing :: Linguistic", + "Topic :: Text Processing :: Markup", + "Topic :: Text Processing :: Markup :: HTML", + "Topic :: Text Processing :: Markup :: XML", + "Topic :: Utilities" +] +dependencies = [ + "BeautifulSoup4>=4.5.1", + "lxml>=3.6.0", + "numpy>=1.9" +] + +[project.optional-dependencies] +full = [ + "boto3>=1.4.2", + "Pillow>=3.1.1", + "requests>=2.9.1", + "tgt>=1.4.2", + "youtube-dl>=2016.9.27", +] +nopillow = [ + "boto3>=1.4.2", + "requests>=2.9.1", + "tgt>=1.4.2", + "youtube-dl>=2016.9.27", +] +boto3 = ["boto3>=1.4.2"] +pillow = ["Pillow>=3.1.1"] +requests = ["requests>=2.9.1"] +tgt = ["tgt>=1.4.2"] + +[project.urls] +Homepage = "https://github.com/readbeyond/aeneas" + +[project.scripts] +aeneas_check_setup = "aeneas.tools.bin.aeneas_check_setup:main" +aeneas_convert_syncmap = "aeneas.tools.bin.aeneas_convert_syncmap:main" +aeneas_download = "aeneas.tools.bin.aeneas_download:main" +aeneas_execute_job = "aeneas.tools.bin.aeneas_execute_job:main" +aeneas_execute_task = "aeneas.tools.bin.aeneas_execute_task:main" +aeneas_plot_waveform = "aeneas.tools.bin.aeneas_plot_waveform:main" +aeneas_synthesize_text = "aeneas.tools.bin.aeneas_synthesize_text:main" +aeneas_validate = "aeneas.tools.bin.aeneas_validate:main" + +[tool.setuptools] +packages = [ + "aeneas", + "aeneas.cdtw", + "aeneas.cew", + "aeneas.cfw", + "aeneas.cmfcc", + "aeneas.cwave", + "aeneas.extra", + "aeneas.syncmap", + "aeneas.tools", + "aeneas.ttswrappers", + "aeneas.tools.bin", +] + +[tool.setuptools.package-data] +"aeneas" = ["res/*", "*.md"] +"aeneas.cdtw" = ["*.c", "*.h", "*.md"] +"aeneas.cew" = ["*.c", "*.h", "*.md", "*.dll", "*.cc"] +"aeneas.cmfcc" = ["*.c", "*.h", "*.md"] +"aeneas.cwave" = ["*.c", "*.h", "*.md"] +"aeneas.extra" = ["*.md"] +"aeneas.syncmap" = ["*.md"] +"aeneas.tools" = ["res/*", "*.md"] +"aeneas.ttswrappers" = ["*.md"] diff --git a/setup.py b/setup.py index e9dd533d..0e8a8cfa 100644 --- a/setup.py +++ b/setup.py @@ -1,203 +1,5 @@ -#!/usr/bin/env python -# coding=utf-8 - -# aeneas is a Python/C library and a set of tools -# to automagically synchronize audio and text (aka forced alignment) -# -# Copyright (C) 2012-2013, Alberto Pettarin (www.albertopettarin.it) -# Copyright (C) 2013-2015, ReadBeyond Srl (www.readbeyond.it) -# Copyright (C) 2015-2018, Alberto Pettarin (www.albertopettarin.it) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -""" -Set the aeneas package up. -""" - - -from setuptools import Extension -from setuptools import setup -from setuptools.command.build_ext import build_ext as BaseBuildExtension -import os -import shutil - -from setupmeta import PKG_AUTHOR -from setupmeta import PKG_AUTHOR_EMAIL -from setupmeta import PKG_CLASSIFIERS -from setupmeta import PKG_EXTRAS_REQUIRE -from setupmeta import PKG_INSTALL_REQUIRES -from setupmeta import PKG_KEYWORDS -from setupmeta import PKG_LICENSE -from setupmeta import PKG_LONG_DESCRIPTION -from setupmeta import PKG_NAME -from setupmeta import PKG_PACKAGES -from setupmeta import PKG_PACKAGE_DATA -from setupmeta import PKG_SCRIPTS -from setupmeta import PKG_SETUP_REQUIRES -from setupmeta import PKG_SHORT_DESCRIPTION -from setupmeta import PKG_URL -from setupmeta import PKG_VERSION - -__author__ = "Alberto Pettarin" -__email__ = "aeneas@readbeyond.it" -__copyright__ = """ - Copyright 2012-2013, Alberto Pettarin (www.albertopettarin.it) - Copyright 2013-2015, ReadBeyond Srl (www.readbeyond.it) - Copyright 2015-2018, Alberto Pettarin (www.albertopettarin.it) -""" -__license__ = "GNU AGPL 3" -__status__ = "Production" -__version__ = "1.7.4" - - -############################################################################## -# -# Windows-specific setup for compiling cew -# -############################################################################## - -def prepare_cew_for_windows(): - """ - Copy files needed to compile the ``cew`` Python C extension on Windows. - - A glorious day, when Microsoft will offer a decent support - for Python and shared libraries, - all this mess will be unnecessary and it should be removed. - May that day come soon. - - Return ``True`` if successful, ``False`` otherwise. - - :rtype: bool - """ - try: - # copy espeak_sapi.dll to C:\Windows\System32\espeak.dll - espeak_dll_win_path = "C:\\Windows\\System32\\espeak.dll" - espeak_dll_dst_path = "aeneas\\cew\\espeak.dll" - espeak_dll_src_paths = [ - "C:\\aeneas\\eSpeak\\espeak_sapi.dll", - "C:\\sync\\eSpeak\\espeak_sapi.dll", - "C:\\Program Files\\eSpeak\\espeak_sapi.dll", - "C:\\Program Files (x86)\\eSpeak\\espeak_sapi.dll", - ] - if os.path.exists(espeak_dll_dst_path): - print("[INFO] Found eSpeak DLL in %s" % espeak_dll_dst_path) - else: - found = False - copied = False - for src_path in espeak_dll_src_paths: - if os.path.exists(src_path): - found = True - print("[INFO] Copying eSpeak DLL from %s into %s" % (src_path, espeak_dll_dst_path)) - try: - shutil.copyfile(src_path, espeak_dll_dst_path) - copied = True - print("[INFO] Copied eSpeak DLL") - except: - pass - break - if not found: - print("[WARN] Unable to find the eSpeak DLL, probably because you installed eSpeak in a non-standard location.") - print("[WARN] If you want to run aeneas with the C extension cew,") - print("[WARN] please copy espeak_sapi.dll from your eSpeak directory to %s" % espeak_dll_win_path) - # print("[WARN] and run the aeneas setup again.") - # return False - elif not copied: - print("[WARN] Unable to copy the eSpeak DLL, probably because you are not running with admin privileges.") - print("[WARN] If you want to run aeneas with the C extension cew,") - print("[WARN] please copy espeak_sapi.dll from your eSpeak directory to %s" % espeak_dll_win_path) - # print("[WARN] and run the aeneas setup again.") - # return False - - # NOTE: espeak.lib is needed only while compiling the C extension, not when using it - # so, we copy it in the current working directory from the included thirdparty\ directory - # NOTE: PREV: copy thirdparty\espeak.lib to $PYTHON\libs\espeak.lib - # NOTE: PREV: espeak_lib_dst_path = os.path.join(sys.prefix, "libs", "espeak.lib") - espeak_lib_src_path = os.path.join(os.path.dirname(__file__), "thirdparty", "espeak.lib") - espeak_lib_dst_path = os.path.join(os.path.dirname(__file__), "espeak.lib") - if os.path.exists(espeak_lib_dst_path): - print("[INFO] Found eSpeak LIB in %s" % espeak_lib_dst_path) - else: - try: - print("[INFO] Copying eSpeak LIB into %s" % espeak_lib_dst_path) - shutil.copyfile(espeak_lib_src_path, espeak_lib_dst_path) - print("[INFO] Copied eSpeak LIB") - except: - print("[WARN] Unable to copy the eSpeak LIB, probably because you are not running with admin privileges.") - print("[WARN] If you want to compile the C extension cew,") - print("[WARN] please copy espeak.lib from the thirdparty directory into %s" % espeak_lib_dst_path) - print("[WARN] and run the aeneas setup again.") - return False - - # if here, we have completed the setup, return True - return True - except Exception as e: - print("[WARN] Unexpected exception while preparing cew: %s" % e) - return False - - -############################################################################## -# -# find the OS out and read environment variables for options -# -############################################################################## - -# get platform -IS_LINUX = (os.name == "posix") and (os.uname()[0] == "Linux") -IS_OSX = (os.name == "posix") and (os.uname()[0] == "Darwin") -IS_WINDOWS = (os.name == "nt") - -# define what values of environment variables are considered equal to True -TRUE_VALUES = [ - "TRUE", - "True", - "true", - "YES", - "Yes", - "yes", - "1", - 1 -] - -# check whether the user set additional parameters using environment variables -# NOTE by the book this should be done by subclassing the setuptools Distribution object -# but for now using environment variables is good enough -WITHOUT_CDTW = os.getenv("AENEAS_WITH_CDTW", "True") not in TRUE_VALUES -WITHOUT_CMFCC = os.getenv("AENEAS_WITH_CMFCC", "True") not in TRUE_VALUES -WITHOUT_CEW = os.getenv("AENEAS_WITH_CEW", "True") not in TRUE_VALUES -FORCE_CEW = os.getenv("AENEAS_FORCE_CEW", "False") in TRUE_VALUES -FORCE_CFW = os.getenv("AENEAS_FORCE_CFW", "False") in TRUE_VALUES - - -############################################################################## -# -# actual setup -# -############################################################################## - -class BuildExtension(BaseBuildExtension): - def finalize_options(self): - BaseBuildExtension.finalize_options(self) - # Prevent numpy from thinking it is still in its setup process: - __builtins__.__NUMPY_SETUP__ = False - import numpy - self.include_dirs.append(numpy.get_include()) - -# scripts to be installed globally -# on Linux and Mac OS X, use the file without extension -# on Windows, use the file with .py extension -if IS_WINDOWS: - PKG_SCRIPTS = [s + ".py" for s in PKG_SCRIPTS] +from setuptools import Extension, setup +from numpy import get_include # prepare Extension objects EXTENSION_CDTW = Extension( @@ -207,6 +9,9 @@ def finalize_options(self): "aeneas/cdtw/cdtw_func.c", "aeneas/cint/cint.c" ], + include_dirs=[ + get_include() + ] ) EXTENSION_CMFCC = Extension( name="aeneas.cmfcc.cmfcc", @@ -216,6 +21,9 @@ def finalize_options(self): "aeneas/cwave/cwave_func.c", "aeneas/cint/cint.c" ], + include_dirs=[ + get_include() + ] ) EXTENSION_CEW = Extension( name="aeneas.cew.cew", @@ -245,110 +53,11 @@ def finalize_options(self): ] ) -CMDCLASS = { - "build_ext": BuildExtension -} - -# cwave is ready, but currently not used -# EXTENSION_CWAVE = Extension( -# name="aeneas.cwave.cwave", -# sources=[ -# "aeneas/cwave/cwave_py.c", -# "aeneas/cwave/cwave_func.c" -# ], -# include_dirs=[ -# get_include() -# ] -# ) - -# append or ignore cew extension as requested -EXTENSIONS = [] - -if WITHOUT_CDTW: - print("[INFO] ************************************************************") - print("[INFO] The user specified AENEAS_WITH_CDTW=False: not building cdtw") - print("[INFO] ************************************************************") - print("[INFO] ") -else: - EXTENSIONS.append(EXTENSION_CDTW) - -if WITHOUT_CMFCC: - print("[INFO] **************************************************************") - print("[INFO] The user specified AENEAS_WITH_CMFCC=False: not building cmfcc") - print("[INFO] **************************************************************") - print("[INFO] ") -else: - EXTENSIONS.append(EXTENSION_CMFCC) - -if WITHOUT_CEW: - print("[INFO] **********************************************************") - print("[INFO] The user specified AENEAS_WITH_CEW=False: not building cew") - print("[INFO] **********************************************************") - print("[INFO] ") -elif FORCE_CEW: - print("[INFO] ********************************************************************************") - print("[INFO] The user specified AENEAS_FORCE_CEW=True: attempting to build cew without checks") - print("[INFO] ********************************************************************************") - print("[INFO] ") - EXTENSIONS.append(EXTENSION_CEW) -else: - if IS_LINUX: - EXTENSIONS.append(EXTENSION_CEW) - elif IS_OSX: - print("[INFO] *********************************************************************************") - print("[INFO] Compiling the C extension cew on Mac OS X is experimental.") - print("[INFO] ") - print("[INFO] Before installing aeneas with cew, you must run:") - print("[INFO] $ brew update && brew upgrade --cleanup espeak") - print("[INFO] to run the new brew formula installing libespeak, the library version of espeak.") - print("[INFO] ") - print("[INFO] If you experience problems, disable cew compilation by specifying") - print("[INFO] the environment variable AENEAS_WITH_CEW=False .") - print("[INFO] Please see the aeneas installation documentation for details.") - print("[INFO] ********************************************************************************") - print("[INFO] ") - EXTENSIONS.append(EXTENSION_CEW) - elif IS_WINDOWS: - print("[INFO] *****************************************************************") - print("[INFO] Compiling the C extension cew on Windows is experimental.") - print("[INFO] ") - print("[INFO] If you experience problems, disable cew compilation by specifying") - print("[INFO] the environment variable AENEAS_WITH_CEW=False .") - print("[INFO] Please see the aeneas installation documentation for details.") - print("[INFO] *****************************************************************") - print("[INFO] ") - if prepare_cew_for_windows(): - EXTENSIONS.append(EXTENSION_CEW) - else: - print("[WARN] Unable to complete the setup for C extension cew, not building it.") - else: - print("[INFO] The C extension cew is not available for your OS.") - -if FORCE_CFW: - print("[INFO] ********************************************************************************") - print("[INFO] The user specified AENEAS_FORCE_CFW=True: attempting to build cfw without checks") - print("[INFO] ********************************************************************************") - print("[INFO] ") - EXTENSIONS.append(EXTENSION_CFW) - -# now we are ready to call setup() setup( - name=PKG_NAME, - version=PKG_VERSION, - packages=PKG_PACKAGES, - package_data=PKG_PACKAGE_DATA, - description=PKG_SHORT_DESCRIPTION, - long_description=PKG_LONG_DESCRIPTION, - author=PKG_AUTHOR, - author_email=PKG_AUTHOR_EMAIL, - url=PKG_URL, - license=PKG_LICENSE, - keywords=PKG_KEYWORDS, - classifiers=PKG_CLASSIFIERS, - cmdclass=CMDCLASS, - setup_requires=PKG_SETUP_REQUIRES, - install_requires=PKG_INSTALL_REQUIRES, - extras_require=PKG_EXTRAS_REQUIRE, - scripts=PKG_SCRIPTS, - ext_modules=EXTENSIONS + ext_modules=[ + EXTENSION_CEW, + EXTENSION_CDTW, + EXTENSION_CMFCC, + EXTENSION_CFW + ] )