diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 79e15f32..cd945e47 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,6 @@ # Overview -Define what you did... - -## Ticket - -Link a pivotal ticket here +Define what you did... why is this change required? What problem does it solve? ## Contributions diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aef8daf5..ad7f513d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -115,9 +115,9 @@ jobs: run: | python -m pip install --upgrade pip brew update + brew uninstall cmake sh scripts/shell/m2chip_install.sh brew install labstreaminglayer/tap/lsl - pip install psychopy --no-deps make install - name: install dependencies run: | @@ -136,7 +136,4 @@ jobs: - name: build run: | make build - - name: codacy - run: | - export CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} - bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r "cobertura.xml" + diff --git a/.github/workflows/publish_to_pypi.yml b/.github/workflows/publish_to_pypi.yml index 59ef92c2..a4f5f9eb 100644 --- a/.github/workflows/publish_to_pypi.yml +++ b/.github/workflows/publish_to_pypi.yml @@ -83,17 +83,16 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} run: >- - gh release create - "$GITHUB_REF_NAME" - --repo "$GITHUB_REPOSITORY" + VERSION=$(python -c "import toml; print(toml.load('pyproject.toml')['project']['version'])") + gh release create \ + "v${VERSION}" \ + --repo "$GITHUB_REPOSITORY" \ --notes "" - name: Upload artifact signatures to GitHub Release env: GITHUB_TOKEN: ${{ github.token }} - # Upload to GitHub Release using the `gh` CLI. - # `dist/` contains the built packages, and the - # sigstore-produced signatures and certificates. - run: >- - gh release upload - "$GITHUB_REF_NAME" dist/** + run: | + VERSION=$(python -c "import toml; print(toml.load('pyproject.toml')['project']['version'])") + gh release upload \ + "v${VERSION}" dist/** \ --repo "$GITHUB_REPOSITORY" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d2f4748..503f21c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 2.0.1 + +- Update PsychoPy to 2025.1.1 +- Update MacOS builds to remove cmake before lsl install +- Fix EEG evidence bug in copy phrase task + # 2.0.0 The next major BciPy release is here! All features included from release canidates rc1-rc4 and contributions described below. diff --git a/bcipy/core/symbols.py b/bcipy/core/symbols.py index 1b642e4f..2318073a 100644 --- a/bcipy/core/symbols.py +++ b/bcipy/core/symbols.py @@ -32,12 +32,12 @@ def alphabet(parameters: Optional[Any] = None, include_path: bool = True, stimulus_array: List[str] = [] for stimulus_filename in sorted(os.listdir(path)): # PLUS.png is reserved for the fixation symbol - if stimulus_filename.endswith( - '.png') and not stimulus_filename.endswith('PLUS.png'): + root, ext = os.path.splitext(stimulus_filename) + if ext in [".png", ".bmp", ".jpg"] and not root.endswith("PLUS"): if include_path: img = os.path.join(path, stimulus_filename) else: - img = os.path.splitext(stimulus_filename)[0] + img = root stimulus_array.append(img) return stimulus_array diff --git a/bcipy/core/tests/resources/images/1x1_PLUS.bmp b/bcipy/core/tests/resources/images/1x1_PLUS.bmp new file mode 100644 index 00000000..b3ae134e Binary files /dev/null and b/bcipy/core/tests/resources/images/1x1_PLUS.bmp differ diff --git a/bcipy/core/tests/resources/images/1x1_PLUS.jpg b/bcipy/core/tests/resources/images/1x1_PLUS.jpg new file mode 100644 index 00000000..d1d27bf7 Binary files /dev/null and b/bcipy/core/tests/resources/images/1x1_PLUS.jpg differ diff --git a/bcipy/core/tests/resources/images/1x1_PLUS.png b/bcipy/core/tests/resources/images/1x1_PLUS.png new file mode 100644 index 00000000..b4bdc430 Binary files /dev/null and b/bcipy/core/tests/resources/images/1x1_PLUS.png differ diff --git a/bcipy/core/tests/resources/images/a_1x1.bmp b/bcipy/core/tests/resources/images/a_1x1.bmp new file mode 100644 index 00000000..b3ae134e Binary files /dev/null and b/bcipy/core/tests/resources/images/a_1x1.bmp differ diff --git a/bcipy/core/tests/resources/images/b_1x1.jpg b/bcipy/core/tests/resources/images/b_1x1.jpg new file mode 100644 index 00000000..d1d27bf7 Binary files /dev/null and b/bcipy/core/tests/resources/images/b_1x1.jpg differ diff --git a/bcipy/core/tests/resources/images/c_1x1.png b/bcipy/core/tests/resources/images/c_1x1.png new file mode 100644 index 00000000..b4bdc430 Binary files /dev/null and b/bcipy/core/tests/resources/images/c_1x1.png differ diff --git a/bcipy/core/tests/resources/images/text.txt b/bcipy/core/tests/resources/images/text.txt new file mode 100644 index 00000000..7a98a964 --- /dev/null +++ b/bcipy/core/tests/resources/images/text.txt @@ -0,0 +1 @@ +Text file for testing only images are collected from the folder. \ No newline at end of file diff --git a/bcipy/core/tests/test_symbols.py b/bcipy/core/tests/test_symbols.py index f3cfce7a..0c3dead8 100644 --- a/bcipy/core/tests/test_symbols.py +++ b/bcipy/core/tests/test_symbols.py @@ -1,7 +1,7 @@ import unittest from bcipy.core.symbols import alphabet - +from typing import Dict class TestAlphabet(unittest.TestCase): def test_alphabet_text(self): @@ -17,15 +17,26 @@ def test_alphabet_text(self): '<', '_' ]) - def test_alphabet_images(self): - parameters = {} + def test_alphabet_images_with_path(self): + path = 'bcipy/core/tests/resources/images/' + parameters: Dict[str, bool | str] = {} parameters['is_txt_stim'] = False - parameters['path_to_presentation_images'] = ('bcipy/static/images/' - 'rsvp/') + parameters['path_to_presentation_images'] = path alp = alphabet(parameters) - self.assertNotEqual(alp, [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'V', 'Y', 'Z', '<', '_' + self.assertEqual(alp, [ + path + 'a_1x1.bmp', + path + 'b_1x1.jpg', + path + 'c_1x1.png' ]) + + def test_alphabet_images_without_path(self): + path = 'bcipy/core/tests/resources/images/' + parameters: Dict[str, bool | str] = {} + parameters['is_txt_stim'] = False + parameters['path_to_presentation_images'] = path + + alp = alphabet(parameters, include_path=False) + + self.assertEqual(alp, ['a_1x1', 'b_1x1', 'c_1x1']) diff --git a/bcipy/display/paradigm/rsvp/display.py b/bcipy/display/paradigm/rsvp/display.py index 2c075eda..b8aa6a27 100644 --- a/bcipy/display/paradigm/rsvp/display.py +++ b/bcipy/display/paradigm/rsvp/display.py @@ -319,7 +319,7 @@ def _generate_inquiry(self) -> List[Dict[str, Any]]: this_stimuli_size = (self.size_list_sti[idx] if self.size_list_sti else self.stimuli_height) - if stim.endswith('.png'): + if any([stim.endswith(ext) for ext in [".png", ".bmp", ".jpg"]]): current_stim['sti'] = self._create_stimulus( mode='image', height=this_stimuli_size, diff --git a/bcipy/gui/BCInterface.py b/bcipy/gui/BCInterface.py index ca097fcd..9ccfe801 100644 --- a/bcipy/gui/BCInterface.py +++ b/bcipy/gui/BCInterface.py @@ -172,8 +172,8 @@ def _build_action_buttons(self) -> None: (self.ui_config.btn_width * 2) + 20 self.add_button( message='Train', - position=(btn_auc_x, 450), - size=(self.ui_config.btn_width, self.ui_config.btn_height), + position=[btn_auc_x, 450], + size=[self.ui_config.btn_width, self.ui_config.btn_height], background_color='LightSeaGreen', text_color='black', font_family=self.ui_config.font, @@ -182,7 +182,7 @@ def _build_action_buttons(self) -> None: def _build_start_button(self) -> None: """Build the Start Session button.""" btn_start_width = self.ui_config.btn_width * 2 + 10 - btn_start_x = self.width - (self.ui_config.padding + btn_start_width) + btn_start_x = self._width - (self.ui_config.padding + btn_start_width) self.add_button( message='Start Session', position=[btn_start_x, 440], @@ -196,7 +196,7 @@ def _build_create_experiment_button(self) -> None: """Build the Create Experiment button.""" self.add_button( message='+', - position=[self.width - self.ui_config.padding - 200, 260], + position=[self._width - self.ui_config.padding - 200, 260], size=[35, self.ui_config.btn_height - 10], background_color='green', action=self.create_experiment, @@ -301,7 +301,7 @@ def build_images(self) -> None: # NEU logo self.add_image( path=f'{STATIC_IMAGES_PATH}/gui/neu.png', - position=[self.width - self.ui_config.padding - 110, 0], + position=[self._width - self.ui_config.padding - 110, 0], size=100) def build_assets(self) -> None: @@ -517,7 +517,7 @@ def load_experiments(self) -> List[str]: Returns: List[str]: List of experiment names. """ - return load_experiments().keys() + return list(load_experiments().keys()) def start_experiment(self) -> None: """Start an experiment session.""" diff --git a/bcipy/parameters/parameters.json b/bcipy/parameters/parameters.json index 79022527..ccbb7fef 100755 --- a/bcipy/parameters/parameters.json +++ b/bcipy/parameters/parameters.json @@ -267,7 +267,7 @@ "value": "bcipy/static/images/rsvp/", "section": "bci_config", "name": "Image Stimulus Folder", - "helpTip": "Specifies the location of image files to be used as stimuli (Text Stimuli On/Off must be set to ‘false’). This must be a directory ending with /.", + "helpTip": "Specifies the location of image files to be used as stimuli (Text Stimuli On/Off must be set to ‘false’). This must be a directory ending with /. Image files must have extension .bmp, .jpg, or .png. Files ending in PLUS.bmp, PLUS.jpg, or PLUS.png, are ignored as they are assumed to be fixation images.", "recommended": "", "editable": false, "type": "directorypath" diff --git a/bcipy/task/control/evidence.py b/bcipy/task/control/evidence.py index 83c6b68c..55afefba 100644 --- a/bcipy/task/control/evidence.py +++ b/bcipy/task/control/evidence.py @@ -61,6 +61,7 @@ def __init__( self.symbol_set = symbol_set self.signal_model = signal_model self.device_spec = device_spec + self.parameters = parameters @property def consumes(self) -> ContentType: @@ -80,7 +81,7 @@ def produces(self) -> EvidenceType: """ raise NotImplementedError() - def evaluate(self, **kwargs: Any) -> np.ndarray: + def evaluate(self, *args: Any, **kwargs: Any) -> np.ndarray: """Evaluate the evidence from raw data. Args: @@ -167,7 +168,8 @@ def evaluate( times: List[float], target_info: List[str], window_length: float, - *args: Any) -> np.ndarray: + *args: Any, + **kwargs: Any) -> np.ndarray: """Evaluate EEG evidence. Args: @@ -270,10 +272,9 @@ def evaluate( raw_data: np.ndarray, symbols: List[str], times: List[float], - target_info: List[str], - window_length: float, flash_time: float, - stim_length: float) -> np.ndarray: + *args: Any, + **kwargs: Any) -> np.ndarray: """Evaluate gaze evidence. Args: @@ -382,7 +383,7 @@ def preprocess( # pylint: disable=arguments-differ def evaluate(self, raw_data: np.ndarray, symbols: List[str], times: List[float], target_info: List[str], - window_length: float) -> np.ndarray: + window_length: float, *args: Any, **kwargs: Any) -> np.ndarray: """Evaluate the evidence. Parameters diff --git a/bcipy/task/paradigm/rsvp/copy_phrase.py b/bcipy/task/paradigm/rsvp/copy_phrase.py index 68f401f8..e646dbfc 100644 --- a/bcipy/task/paradigm/rsvp/copy_phrase.py +++ b/bcipy/task/paradigm/rsvp/copy_phrase.py @@ -648,7 +648,7 @@ def evaluate_evidence(self) -> Decision: return Decision(decision_made, selection, spelled_text, new_sti) def add_evidence( - self, stim_times: List[List], proceed: bool = True + self, stim_times: List[Tuple], proceed: bool = True ) -> List[EvidenceType]: """Add all evidence used to make a decision. diff --git a/pyproject.toml b/pyproject.toml index c7c9cd05..4ed27054 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ requires = ["setuptools>=61.0", "wheel>=0.37.1"] [project] name = "bcipy" -version = "2.0.0" +version = "2.0.1" authors = [ {name="CAMBI", email="cambi_support@googlegroups.com"}, ] @@ -34,7 +34,7 @@ dependencies = [ "pybv==0.7.5", "pyo==1.0.5", "pyglet<=1.5.27,>=1.4", - "PsychoPy==2024.2.1", + "PsychoPy==2025.1.1", "openpyxl==3.1.2", "numpy==1.24.4", "sounddevice==0.4.4",