diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..75cc1e3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,40 @@ +name: Bug Report +description: The software does something unwanted or unusual +title: "[BUG]: " +labels: ["bug"] + +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: checkboxes + id: new-bug + attributes: + label: Did you search for similar bugs? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: false + - type: textarea + id: bug-description + attributes: + label: What happened? + description: Tell us what bug you encountered + validations: + required: true + - type: textarea + id: bug-behaviour + attributes: + label: Expectations? + description: Tell us what should have happened + validations: + required: true + - type: textarea + id: steps-to-reproduce + attributes: + label: Steps To Reproduce + description: Can you describe your steps, when you encountered the bug? + placeholder: Please write the steps in a list form + validations: + required: false \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7d04f9b..5a4b3a8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.wav build/* docs/_build +*.code-workspace *.swp *.orig env diff --git a/README.md b/README.md index 9ba3b6a..04a639c 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,16 @@ You can find user support for installing and using the FAVE toolkits at the [FAV ## Contributing to FAVE For the most part, we'll be utilizing the fork-and-pull paradigm (see [Using Pull Requests](https://help.github.com/articles/using-pull-requests)). Please send pull requests to the `dev` branch. -If you want to keep up to date on FAVE development, or have questions about FAVE development, send a request to join the [FAVE Developers' Group](https://groups.google.com/forum/#!forum/fave-dev). +You can fill in a bug report at the [issue tab](https://github.com/JoFrhwld/FAVE/issues) + +There may be a delay between when a bug is reported and when a bug is resolved. Developers prioritize bugs based on difficulty, importance, and other factors, so bug reports are usually not handled in the order they are received. ## Attribution -[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.22281.svg)](http://dx.doi.org/10.5281/zenodo.22281) +[![DOI](https://zenodo.org/badge/13744621.svg)](https://zenodo.org/badge/latestdoi/13744621) +![GitHub](https://img.shields.io/github/license/JoFrhwld/FAVE) +![GitHub](https://img.shields.io/badge/Python-3.8%2B-brightgreen) +[![PyPI version fury.io](https://badge.fury.io/py/fave.svg)](https://pypi.python.org/pypi/fave/) + As of v1.1.3 onwards, releases from this repository will have a DOI associated with them through Zenodo. The DOI for the current release is [10.5281/zenodo.22281](http://dx.doi.org/10.5281/zenodo.22281). We would recommend the citation: Rosenfelder, Ingrid; Fruehwald, Josef; Brickhouse, Christian; Evanini, Keelan; Seyfarth, Scott; Gorman, Kyle; Prichard, Hilary; Yuan, Jiahong; 2022. FAVE (Forced Alignment and Vowel Extraction) Program Suite v2.0.0 */zenodo.* diff --git a/fave/align/transcriptprocessor.py b/fave/align/transcriptprocessor.py index d9a2d95..34e0957 100644 --- a/fave/align/transcriptprocessor.py +++ b/fave/align/transcriptprocessor.py @@ -247,7 +247,13 @@ def read_transcription_file(self): """Reads file into memory""" with open(self.file) as f: lines = self.replace_smart_quotes(f.readlines()) - self.lines = lines + self.lines = lines + try: + float(lines[0].split('\t')[2]) + except ValueError: + # Log a warning about having detected a header row + self.logger.warning('Header row was detected') + del lines[0] # substitute any 'smart' quotes in the input file with the corresponding # ASCII equivalents (otherwise they will be excluded as out-of- diff --git a/poetry.lock b/poetry.lock index 717a74f..e52dcbd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -803,41 +803,6 @@ pytz = [ {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"}, {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"}, ] -pyyaml = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] requests = [] snowballstemmer = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, diff --git a/pyproject.toml b/pyproject.toml index 30acf2b..46b573b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fave" -version = "2.0.2-dev" +version = "2.0.3-dev" description = "Forced alignment and vowel extraction" authors = [ "Ingrid Rosenfelder", diff --git a/tests/fave/align/test_transcriptprocessor.py b/tests/fave/align/test_transcriptprocessor.py index 8854167..873d266 100644 --- a/tests/fave/align/test_transcriptprocessor.py +++ b/tests/fave/align/test_transcriptprocessor.py @@ -1,5 +1,27 @@ +import logging import pytest from fave.align import transcriptprocessor +from fave import cmudictionary # We shouldn't be doing this... + +# Copied from ../test_cmudictionary.py +# which means this really should be made a fixture... +KWARGS = { + 'verbose': 1 + } + +CMU_EXCERPT = """ +TEST T EH1 S T +TEST'S T EH1 S T S +TESTA T EH1 S T AH0 +TESTAMENT T EH1 S T AH0 M AH0 N T +TESTAMENTARY T EH2 S T AH0 M EH1 N T ER0 IY0 +TESTED T EH1 S T AH0 D +TESTER T EH1 S T ER0 +TESTERMAN T EH1 S T ER0 M AH0 N +TESTERS T EH1 S T ER0 Z +TESTERS T EH1 S T AH0 Z +""" + def test_replace_smart_quotes(): def test_func( testcase ): @@ -69,3 +91,57 @@ def provide_check_transcription_format_raises_value_error(): # Skip 5 entries (not an error) [ 'a\tb\tc\td\te\tf', ValueError], # 6 entries ] + +def test_read_transcription_file(tmp_path): + tmp_directory = tmp_path / "transcripts" + tmp_directory.mkdir() + tmp_file = tmp_directory / "test_transcript.csv" + dict_file = tmp_directory / "cmu.dict" + dict_file.write_text(CMU_EXCERPT) + cmu_dict = cmudictionary.CMU_Dictionary(dict_file, **KWARGS) + for test_case in provide_value_error_file(): + test_text = test_case[0] + flags = test_case[1] + expected = test_case[2] + tmp_file.write_text(test_text) + tp_obj = transcriptprocessor.TranscriptProcessor( + tmp_file, + cmu_dict, + **flags + ) + tp_obj.read_transcription_file() + + assert tp_obj.lines == expected + +def provide_value_error_file(): + return [ + [ # header row is detected and deleted + "Style\tSpeaker\tBeginning\tEnd\tDuration\nFoo\tBar\t0.0\t3.2\t3.2", + { + 'prompt': "IDK what this is -CJB", + 'check' : '', + 'verbose': logging.DEBUG + }, + ['Foo\tBar\t0.0\t3.2\t3.2'] + ], + [ # test with one line + "Foo\tBar\t0.0\t3.2\t3.2\nTest\t1.0\t4.5\t3.5", + { + 'prompt': "IDK what this is -CJB", + 'check' : '', + 'verbose': logging.DEBUG + }, + ['Foo\tBar\t0.0\t3.2\t3.2\n', 'Test\t1.0\t4.5\t3.5'] + ], + [ # test with more lines + "Foo\tBar\t0.0\t3.2\t3.2\nTest\t1.0\t4.5\t3.5\nTest\t1.0\t4.5\t3.5", + { + 'prompt': "IDK what this is -CJB", + 'check' : '', + 'verbose': logging.DEBUG + }, + ['Foo\tBar\t0.0\t3.2\t3.2\n', 'Test\t1.0\t4.5\t3.5\n', 'Test\t1.0\t4.5\t3.5'] + ] + + ] + diff --git a/tests/fave/extract/test_extractFormants.py b/tests/fave/extract/test_extractFormants.py new file mode 100644 index 0000000..e30ebe6 --- /dev/null +++ b/tests/fave/extract/test_extractFormants.py @@ -0,0 +1,57 @@ + +import logging +import pytest +import numpy as np +from fave import extractFormants + +def test_mean_stdv(): + for test_case in provide_valuelist(): + mean, stdv = extractFormants.mean_stdv(test_case[0]) + + assert mean == test_case[1] + assert stdv == test_case[2] + +def provide_valuelist(): + return [ + [ + [1, 2, 3, 4], + np.mean([1, 2, 3, 4]), + np.std([1, 2, 3, 4], ddof=1) + ], + [ + [3.5, 2.6, 11.6, 34.66, 2.8, 4.7], + np.mean([3.5, 2.6, 11.6, 34.66, 2.8, 4.7]), + np.std([3.5, 2.6, 11.6, 34.66, 2.8, 4.7], ddof=1) + ], + [ + [], + None, + None + ], + [ + [23, 34, 45, 56, 12, 312, 45, 943, 21, 1, 4, 6, 9, 2], + np.mean([23, 34, 45, 56, 12, 312, 45, 943, 21, 1, 4, 6, 9, 2]), + np.std([23, 34, 45, 56, 12, 312, 45, 943, 21, 1, 4, 6, 9, 2], ddof=1) + ], + [ + [3], + np.mean([3]), + 0 + ], + [ + [-1], + np.mean([-1]), + 0 + ] + [ + [3.5, 2.6, 11.6, None, 34.66, 2.8, 4.7], + np.nanmean(np.array([3.5, 2.6, 11.6, None, 34.66, 2.8, 4.7], + dtype=np.float64)), + np.nanstd(np.array([3.5, 2.6, 11.6, None, 34.66, 2.8, 4.7], + dtype=np.float64), + ddof=1) + ] + ] + + +