diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..8b3e681 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,42 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/python +{ + "name": "Python 3", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/python:1-3.11", + "features": { + "ghcr.io/rocker-org/devcontainer-features/quarto-cli:1": { + "version": "latest" + }, + "ghcr.io/devcontainers-contrib/features/poetry:2": { + "version": "latest" + } + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "poetry install", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": + ["ms-toolsai.jupyter", + "ms-python.vscode-pylance", + "njpwerner.autodocstring"], + "settings": {"python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true} + } + } + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/workflows/test-and-run.yml b/.github/workflows/test-and-run.yml index e76c721..0767718 100644 --- a/.github/workflows/test-and-run.yml +++ b/.github/workflows/test-and-run.yml @@ -22,7 +22,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: "pip" @@ -41,6 +41,6 @@ jobs: run: | python -m pytest --cov=./ --cov-report=xml tests/ - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 76c97eb..e787476 100644 --- a/.gitignore +++ b/.gitignore @@ -160,4 +160,5 @@ cython_debug/ #.idea/ .vscode -poetry.lock \ No newline at end of file +poetry.lock +.DS_Store \ No newline at end of file diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..9f0e6fe --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,26 @@ +# This CITATION.cff file was generated with cffinit. +# Visit https://bit.ly/cffinit to generate yours today! + +cff-version: 1.2.0 +title: fasttrackpy +message: >- + If you use this software, please cite it using the + metadata from this file. +type: software +authors: + - given-names: Josef + family-names: Fruehwald + orcid: 'https://orcid.org/0000-0001-8480-9461' + affiliation: University of Kentucky + - given-names: Santiago + family-names: Barreda + affiliation: UC Davis + orcid: 'https://orcid.org/0000-0002-1552-083X' +identifiers: + - type: doi + value: 10.5281/zenodo.10212100 + description: zenodo +repository-code: 'https://github.com/FastTrackiverse/fasttrackpy' +url: 'https://fasttrackiverse.github.io/fasttrackpy/' +abstract: A python implementation of FastTrack +license: MIT diff --git a/README.md b/README.md index f968530..0c98302 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # FastTrackPy [![PyPI](https://img.shields.io/pypi/v/fasttrackpy)](https://pypi.org/project/fasttrackpy/) -[![Python CI](https://github.com/JoFrhwld/fasttrackpy/actions/workflows/test-and-run.yml/badge.svg)](https://github.com/JoFrhwld/fasttrackpy/actions/workflows/test-and-run.yml) [![codecov](https://codecov.io/gh/FastTrackiverse/fasttrackpy/graph/badge.svg?token=GOAWY4B5C8)](https://codecov.io/gh/FastTrackiverse/fasttrackpy) +[![Python CI](https://github.com/JoFrhwld/fasttrackpy/actions/workflows/test-and-run.yml/badge.svg)](https://github.com/JoFrhwld/fasttrackpy/actions/workflows/test-and-run.yml) [![codecov](https://codecov.io/gh/FastTrackiverse/fasttrackpy/graph/badge.svg?token=GOAWY4B5C8)](https://codecov.io/gh/FastTrackiverse/fasttrackpy) [![DOI](https://zenodo.org/badge/580169086.svg)](https://zenodo.org/doi/10.5281/zenodo.10212099) + Goal: A FastTrack python implementation with importable modules @@ -14,4 +15,4 @@ pip install fasttrackpy ```bash fasttrack --file audio.wav --output formants.csv -``` \ No newline at end of file +``` diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 0000000..ab1033b --- /dev/null +++ b/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/pyproject.toml b/pyproject.toml index 3c9cf0b..2d26bbe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,10 +18,10 @@ homepage = "https://fasttrackiverse.github.io/fasttrackpy/" repository = "https://github.com/FastTrackiverse/fasttrackpy" [tool.poetry.dependencies] -python = ">=3.10,<3.13" +python = ">=3.10,<3.12" praat-parselmouth = "^0.4.3" -scipy = {version = "^1.11.3", python = ">=3.10,<3.13"} -numpy = {version = "^1.26.1", python = ">=3.10,<3.13"} +scipy = {version = "^1.11.3", python = ">=3.10,<3.12"} +numpy = {version = "^1.26.1", python = ">=3.10,<3.12"} polars = "^0.19.16" pytest-cov = "^4.1.0" pytest = "^7.4.3" @@ -59,7 +59,8 @@ addopts = [ "--import-mode=importlib", "--cov-config=tests/.coveragerc", "--cov-report=xml", - "--cov" + "--cov", + "--log-cli-level=INFO" ] filterwarnings =[ "ignore::UserWarning" diff --git a/src/fasttrackpy/cli.py b/src/fasttrackpy/cli.py index 92a5c67..4050e17 100644 --- a/src/fasttrackpy/cli.py +++ b/src/fasttrackpy/cli.py @@ -251,7 +251,8 @@ def audio( n_formants: int = 4, window_length: float = 0.025, time_step: float = 0.002, - pre_emphasis_from: float = 50 + pre_emphasis_from: float = 50, + **kwargs ): """Run fasttrack. @@ -392,7 +393,8 @@ def audio_textgrid( n_formants: int = 4, window_length: float = 0.025, time_step: float = 0.002, - pre_emphasis_from: float = 50 + pre_emphasis_from: float = 50, + **kwargs ): """Run fasttrack. diff --git a/tests/test_cli.py b/tests/test_cli.py index a151fe8..f235bc2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,6 +3,7 @@ from click.testing import CliRunner import pytest import yaml +import logging class TestCLI: sound_path = Path("tests", "test_data", "ay.wav") @@ -16,17 +17,21 @@ def test_file_usage(self): out_dir.mkdir() runner = CliRunner() - runner.invoke( + result = runner.invoke( fasttrack, - f"audio --file {str(self.sound_path)} --dest {str(out_dir)}" + ["audio", + "--file", self.sound_path, + "--dest", out_dir] ) + + assert result.exit_code == 0, result.output out_files = list(out_dir.glob("*")) - assert all([x.is_file() for x in out_files]) [x.unlink() for x in out_files] out_dir.rmdir() def test_config_file(self): - with open("tests/test_data/config.yml") as file: + config_path = Path("tests", "test_data", "config.yml") + with config_path.open() as file: params = yaml.safe_load(file) sound_path = Path(params["file"]) @@ -35,12 +40,14 @@ def test_config_file(self): dest.mkdir() runner = CliRunner() - runner.invoke( + result = runner.invoke( fasttrack, - f"audio --config tests/test_data/config.yml" + ["audio", + "--config", config_path] ) + + assert result.exit_code == 0, result.output out_files = list(dest.glob("*")) - assert all([x.is_file() for x in out_files]) [x.unlink() for x in out_files] dest.rmdir() @@ -51,14 +58,15 @@ def test_dir_usage(self): out_dir.mkdir() runner = CliRunner() - runner.invoke( + result = runner.invoke( fasttrack, - f"audio --dir {str(self.sound_path.parent)} --dest {str(out_dir)}" + ["audio", + "--dir", self.sound_path.parent, + "--dest", out_dir] ) - out_files = list(out_dir.glob("*")) - assert all([x.is_file() for x in out_files]) - + assert result.exit_code == 0, result.output + out_files = out_dir.glob("*") [x.unlink() for x in out_files] out_dir.rmdir() @@ -67,13 +75,18 @@ def test_audio_tg(self): if not out_dir.is_dir(): out_dir.mkdir() runner = CliRunner() - runner.invoke( + result = runner.invoke( fasttrack, - f"audio-textgrid --audio {str(self.audio_path)} --textgrid {str(self.tg_path)} --target-tier Phone --target-labels AY --dest {str(out_dir)}" + ["audio-textgrid", + "--audio", self.audio_path, + "--textgrid", self.tg_path, + "--target-tier", "Phone", + "--target-labels", "AY", + "--dest", out_dir] ) + assert result.exit_code == 0, result.output out_files = list(out_dir.glob("*")) - assert all([x.is_file() for x in out_files]) [x.unlink() for x in out_files] out_dir.rmdir() @@ -83,14 +96,18 @@ def test_corpus(self): if not out_dir.is_dir(): out_dir.mkdir() runner = CliRunner() - runner.invoke( + result = runner.invoke( fasttrack, - f"corpus --corpus {str(self.corpus_path)} --target-labels AY --dest {str(out_dir)} --separate-output" + ["corpus", + "--corpus", self.corpus_path, + "--target-labels", "AY", + "--dest", out_dir, + "--separate-output"] ) + assert result.exit_code == 0, result.output out_files = list(out_dir.iterdir()) - assert all([x.is_file() for x in out_files]) - #assert len(out_files) > 1 + assert len(out_files) > 1 [x.unlink() for x in out_files] out_dir.rmdir()