diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f88d36572..bb31222df 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install run: | sudo apt-get install sox ninja-build @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install run: | sudo apt-get install sox ninja-build @@ -33,29 +33,47 @@ jobs: - name: Run tests run: | cmake --build build --target check - pytest: - runs-on: ubuntu-latest + python-tests: + name: test with ${{ matrix.py }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + py: + - "3.12" + - "3.11" + - "3.10" + - "3.9" + - "3.8" + os: + - ubuntu-latest + - macos-latest + - windows-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install - run: | - sudo apt-get install sox - python -m pip install --upgrade pip - pip install -r requirements.dev.txt - pip install . - - name: Run tests - run: pytest + - uses: actions/checkout@v4 + - name: Setup python for test ${{ matrix.py }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.py }} + - name: Install sox + if: ${{ startsWith(matrix.os, 'ubuntu') }} + run: sudo apt-get install sox + - name: Install tox + run: python -m pip install tox-gh>=1.2 + - name: Setup test suite + run: tox -vv --notest + - name: Run test suite + run: tox --skip-pkg-install pytest-editable: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install run: | sudo apt-get install sox python -m pip install --upgrade pip - pip install -r requirements.dev.txt + pip install pytest memory_profiler pip install -e . - name: Run tests run: pytest diff --git a/.gitignore b/.gitignore index 2a70e1b52..6d2dbdd2d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ CTestTestfile.cmake DartConfiguration.tcl cmake_install.cmake +.tox diff --git a/.readthedocs.yml b/.readthedocs.yml index 0dcb2b426..d764d78e6 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.9" + python: "3.10" sphinx: configuration: docs/source/conf.py diff --git a/cython/CMakeLists.txt b/cython/CMakeLists.txt index 26619f564..daa4f7643 100644 --- a/cython/CMakeLists.txt +++ b/cython/CMakeLists.txt @@ -1,14 +1,19 @@ -find_package(PythonExtensions REQUIRED) -find_package(Python COMPONENTS Interpreter Development) -find_package(Cython) +find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) +find_program(CYTHON "cython") if(NOT USE_INSTALLED_POCKETSPHINX) set_property(TARGET pocketsphinx PROPERTY POSITION_INDEPENDENT_CODE on) endif() -add_cython_target(_pocketsphinx _pocketsphinx.pyx) -add_library(_pocketsphinx MODULE ${_pocketsphinx}) -target_link_libraries(_pocketsphinx pocketsphinx) +add_custom_command( + OUTPUT _pocketsphinx.c + DEPENDS _pocketsphinx.pyx + VERBATIM + COMMAND "${CYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/_pocketsphinx.pyx" --output-file + "${CMAKE_CURRENT_BINARY_DIR}/_pocketsphinx.c") + +python_add_library(_pocketsphinx MODULE "${CMAKE_CURRENT_BINARY_DIR}/_pocketsphinx.c" WITH_SOABI) +target_link_libraries(_pocketsphinx PRIVATE pocketsphinx) target_include_directories( _pocketsphinx PRIVATE ${PYTHON_INCLUDE_DIR} _pocketsphinx PRIVATE ${CMAKE_BINARY_DIR} @@ -18,8 +23,7 @@ target_include_directories( _pocketsphinx INTERFACE ${CMAKE_SOURCE_DIR}/include _pocketsphinx INTERFACE ${CMAKE_BINARY_DIR}/include ) -python_extension_module(_pocketsphinx) -install(TARGETS _pocketsphinx LIBRARY DESTINATION cython/pocketsphinx) +install(TARGETS _pocketsphinx LIBRARY DESTINATION pocketsphinx) if(NOT USE_INSTALLED_POCKETSPHINX) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/model DESTINATION cython/pocketsphinx) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/model DESTINATION pocketsphinx) endif() diff --git a/cython/_pocketsphinx.pyx b/cython/_pocketsphinx.pyx index 3e3ecead9..15ded6243 100644 --- a/cython/_pocketsphinx.pyx +++ b/cython/_pocketsphinx.pyx @@ -610,7 +610,7 @@ cdef class NGramModel: cdef const char **cwords cdef int prob bwords = [w.encode("utf-8") for w in words] - cwords = malloc(len(bwords)) + cwords = malloc(len(bwords) * sizeof(char *)) for i, w in enumerate(bwords): cwords[i] = w prob = ngram_prob(self.lm, cwords, len(words)) diff --git a/cython/pocketsphinx/__init__.py b/cython/pocketsphinx/__init__.py index c7e009e00..28dd97ab4 100644 --- a/cython/pocketsphinx/__init__.py +++ b/cython/pocketsphinx/__init__.py @@ -33,6 +33,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import collections +import importlib.util import os import signal from contextlib import contextmanager @@ -81,7 +82,10 @@ def get_model_path(subpath=None): """ model_path = pocketsphinx._ps_default_modeldir() if model_path is None: - model_path = os.path.join(os.path.dirname(__file__), "model") + # Use importlib to find things (so editable installs work) + model_path = importlib.util.find_spec( + "pocketsphinx.model" + ).submodule_search_locations[0] if subpath is not None: return os.path.join(model_path, subpath) else: @@ -181,6 +185,7 @@ class AudioFile(Pocketsphinx): simple. """ + def __init__(self, audio_file=None, **kwargs): signal.signal(signal.SIGINT, self.stop) @@ -239,6 +244,7 @@ def __init__(self, **kwargs): try: import sounddevice + assert sounddevice except Exception as e: # In case PortAudio is not present, for instance diff --git a/cython/test/endpointer_test.py b/cython/test/endpointer_test.py index 8e09a4f92..18bee77c9 100644 --- a/cython/test/endpointer_test.py +++ b/cython/test/endpointer_test.py @@ -243,11 +243,14 @@ def srtest(self, sample_rate): idx += 1 def testEndpointer(self): - set_loglevel("INFO") - # 8000, 44100, 48000 give slightly different results unfortunately - for sample_rate in 11025, 16000, 22050, 32000: - print(sample_rate) - self.srtest(sample_rate) + try: + set_loglevel("INFO") + # 8000, 44100, 48000 give slightly different results unfortunately + for sample_rate in 11025, 16000, 22050, 32000: + print(sample_rate) + self.srtest(sample_rate) + except OSError as err: + self.skipTest("sox not installed: %s" % err) if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index cd8964fa6..a8731358a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,38 @@ [build-system] requires = [ - "wheel", - "setuptools>=45,<64", - "scikit-build~=0.15", - "Cython", - "cmake", - "ninja" + "scikit-build-core", + "Cython" ] -build-backend = "setuptools.build_meta" +build-backend = "scikit_build_core.build" + +[project] +name = "pocketsphinx" +version = "5.0.3" +description = "Official Python bindings for PocketSphinx" +readme = "cython/README.md" +authors = [ + {name = "David Huggins-Daines", email = "dhdaines@gmail.com"} +] +keywords = ["asr", "speech"] +classifiers = [ + "Development Status :: 6 - Mature", + "Programming Language :: C", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", +] + +[project.urls] +Homepage = "https://github.com/cmusphinx/pocketsphinx" +Documentation = "https://pocketsphinx.readthedocs.io/en/latest/" +Repository = "https://github.com/cmusphinx/pocketsphinx.git" +Issues = "https://github.com/cmusphinx/pocketsphinx/issues" + [tool.cibuildwheel] # Build the versions found in Ubuntu LTS, the stable PyPy, and 3.10 # everywhere else @@ -22,3 +47,15 @@ build = [ before-build = "rm -rf _skbuild" # PyPy builds are broken on Windows, and skip 32-bit and musl skip = ["*musl*", "*_i686", "*-win32", "pp*win*"] + +[tool.isort] +profile = "black" + +[tool.flake8] +extend-ignore = "E203" +max-line-length = "88" + +[tool.scikit-build] +cmake.verbose = true +logging.level = "INFO" +wheel.packages = ["cython/pocketsphinx"] diff --git a/requirements.dev.txt b/requirements.dev.txt deleted file mode 100644 index 7557df8da..000000000 --- a/requirements.dev.txt +++ /dev/null @@ -1,6 +0,0 @@ -cmake~=3.22.0 -scikit-build~=0.15.0 -Cython~=0.29.0 -setuptools>=45.0.0 -pytest~=7.0.0 -memory-profiler==0.60.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index df41a2d51..000000000 --- a/setup.cfg +++ /dev/null @@ -1,27 +0,0 @@ -[metadata] -name = pocketsphinx -version = 5.0.2 -description = Official Python bindings for PocketSphinx -long_description = file: cython/README.md -long_description_content_type = text/markdown -author = David Huggins-Daines -author_email = dhdaines@gmail.com -license = MIT -platforms = any -url = https://github.com/cmusphinx/pocketsphinx -project_urls = - Source = https://github.com/cmusphinx/pocketsphinx - Tracker = https://github.com/cmusphinx/pocketsphinx/issues -keywords = asr, speech -classifiers = - Development Status :: 3 - Alpha - Programming Language :: C - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.7 - License :: OSI Approved :: MIT License - Operating System :: OS Independent -[isort] -profile=black -[flake8] -extend-ignore = E203 -max-line-length = 88 diff --git a/setup.py b/setup.py deleted file mode 100644 index 73dabc6b7..000000000 --- a/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from skbuild import setup -from setuptools import find_packages - -setup( - packages=find_packages('cython', exclude=["test"]), - package_dir={"": "cython"}, - cmake_languages=["C"], - install_requires=["sounddevice"], -) diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..08ce4b633 --- /dev/null +++ b/tox.ini @@ -0,0 +1,21 @@ +[tox] +env_list = py{38,39,310,311,312} +minversion = 4.11.4 + +[testenv] +description = run the tests with pytest +package = wheel +wheel_build_env = .pkg +deps = + pytest>=6 + memory_profiler +commands = + pytest {tty:--color=yes} {posargs} + +[gh] +python = + 3.12 = py312 + 3.11 = py311 + 3.10 = py310 + 3.9 = py39 + 3.8 = py38