diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index fa7e645..0000000 --- a/.coveragerc +++ /dev/null @@ -1,20 +0,0 @@ -[run] -source = - orangecontrib/storynavigation -omit = - orangecontrib/storynavigation/tests/* - orangecontrib/storynavigation/widgets/tests/* - -[report] -exclude_lines = - pragma: no cover - def __repr__ - - # Don't complain if tests don't hit defensive assertion code: - raise AssertionError - raise NotImplementedError - - - # Don't complain if non-runnable code isn't run: - if 0: - if __name__ == .__main__.: diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index e906a14..4518e2a 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -45,24 +45,3 @@ jobs: path: dist/ - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - - publish-to-test_pypi: - name: Publish distribution to Test PyPI - needs: [build] - runs-on: ubuntu-latest - if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' - environment: - name: testpypi - url: https://test.pypi.org/p/storynavigator - permissions: - id-token: write # IMPORTANT: mandatory for trusted publishing - steps: - - name: Download the distribution packages - uses: actions/download-artifact@v3 - with: - name: artifact - path: dist/ - - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/publish-to-testpypi.yml b/.github/workflows/publish-to-testpypi.yml deleted file mode 100644 index d4faf91..0000000 --- a/.github/workflows/publish-to-testpypi.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Build and publish orange-story-navigator release to TEST PyPI - -on: - push: - branches: - - 'test-release' - -jobs: - build: - name: Build distribution - runs-on: ubuntu-latest - steps: - - name: Repo checkout - uses: actions/checkout@v3 - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.9.13' - - name: Install build - run: python3 -m pip install build - - name: Build a binary wheel and a source tarball - run: python3 -m build - - name: Store the distribution packages - uses: actions/upload-artifact@v3 - with: - name: artifact - path: dist/ - - publish-to-test_pypi: - name: Publish distribution to Test PyPI - needs: [build] - runs-on: ubuntu-latest - if: github.event_name == 'push' - environment: - name: testpypi - url: https://test.pypi.org/p/teststorynavigator # should match trusted publisher name on pypi - permissions: - contents: read - id-token: write # IMPORTANT: mandatory for trusted publishing - steps: - - name: Download the distribution packages - uses: actions/download-artifact@v3 - with: - name: artifact - path: dist/ - - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ # diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 77574ae..098e58e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,35 +10,46 @@ on: pull_request: branches: - master + types: + - opened + - reopened + - synchronize + - ready_for_review + workflow_dispatch: jobs: - build: + test: + if: github.event.pull_request.draft == false + name: Run Tests runs-on: ubuntu-latest strategy: - fail-fast: false matrix: os: ["ubuntu-latest", "windows-latest", "macos-latest"] - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.9"] steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install flake8 tox - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - # - name: Lint with flake8 - # run: | - # # stop the build if there are Python syntax errors or undefined names - # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with Tox - run: | - tox -vv - env: - QT_QPA_PLATFORM: offscreen + - uses: actions/checkout@v3 + with: + submodules: 'true' + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - uses: actions/cache@v3 + id: cache-virtualenv + with: + path: ${{ env.pythonLocation }} + key: ${{ env.pythonLocation }}-${{ hashFiles('setup.cfg') }} + + - name: Install dependencies + if: steps.cache-virtualenv.outputs.cache-hit != 'true' + run: | + python -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu + python -m pip install -e .[dev] + + - name: Test with pytest + run: | + pytest + env: + QT_QPA_PLATFORM: offscreen diff --git a/.gitignore b/.gitignore index 77fa5eb..8de1888 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ flenv/ .venv/ data/ -workflows/ navigator.code-workspace diff --git a/README.md b/README.md index 9695147..dcaa224 100644 --- a/README.md +++ b/README.md @@ -89,5 +89,18 @@ Steps to build and test from source: The Orange3 application should shortly start up with a splash screen +## Testing + +Run tests with `pytest`. + +For coverage: + +```python +coverage run -m pytest +coverage report +# or +coverage html +``` + ## Collaborators The Story Navigator is maintained by the [Netherlands eScience Center](https://www.esciencecenter.nl/) in collaboration with the [Faculty of Behavioural, Management and Social Sciences (BMS)](https://www.utwente.nl/en/bms/) at the [University of Twente](https://www.utwente.nl/en/). diff --git a/orangecontrib/storynavigation/modules/actoranalysis.py b/orangecontrib/storynavigation/modules/actoranalysis.py index 602d296..a20c55a 100644 --- a/orangecontrib/storynavigation/modules/actoranalysis.py +++ b/orangecontrib/storynavigation/modules/actoranalysis.py @@ -1,7 +1,10 @@ """Modules required for Actor Analysis widget in Story Navigator. """ -import sys + +from __future__ import annotations + import os +import sys import pandas as pd import numpy as np import storynavigation.modules.constants as constants @@ -195,7 +198,7 @@ def __postag_sents( return self.html_result def postag_text( - self, text, nouns, subjs, custom, selected_prominence_metric, prominence_score_min, story_elements_df + self, text, nouns: bool, subjs: bool, custom: bool, selected_prominence_metric: float, prominence_score_min: int, story_elements_df: pd.DataFrame | None ): """POS-tags story text and returns HTML string which encodes the the tagged text, ready for rendering in the UI @@ -205,22 +208,23 @@ def postag_text( subjs (boolean): whether subject tokens should be tagged custom (boolean): whether custom tags should be highlighted or not selected_prominence_metric (float): the selected metric by which to calculate the word prominence score - prominence_score_min (float): the minimum prominence score for an entity which qualifies it to be tagged + prominence_score_min (int): the minimum prominence score for an entity which qualifies it to be tagged story_elements_df (pandas.DataFrame): a dataframe with all required nlp tagging information Returns: string: HTML string representation of POS tagged text """ - + + if story_elements_df is None or (len(story_elements_df) == 0): + sentences = util.preprocess_text(text) + return self.__print_html_no_highlighted_tokens(sentences) + story_elements_df['sentence_id'] = pd.to_numeric(story_elements_df['sentence_id']) story_elements_df['storyid'] = pd.to_numeric(story_elements_df['storyid']) sorted_df = story_elements_df.sort_values(by=['storyid', 'sentence_id'], ascending=True) sentences_df = sorted_df[['sentence','storyid','sentence_id']].drop_duplicates() sentences = sentences_df['sentence'].tolist() - - if story_elements_df is None or len(story_elements_df) == 0: - return self.__print_html_no_highlighted_tokens(sentences) - + selected_storyid = story_elements_df['storyid'].unique().tolist()[0] specific_tag_choice_html = (str(int(nouns)) + str(int(subjs)) + str(int(custom))) if selected_storyid in self.tagging_cache: diff --git a/orangecontrib/storynavigation/widgets/OWSNActorAnalysis.py b/orangecontrib/storynavigation/widgets/OWSNActorAnalysis.py index e1bb0df..b21c36f 100644 --- a/orangecontrib/storynavigation/widgets/OWSNActorAnalysis.py +++ b/orangecontrib/storynavigation/widgets/OWSNActorAnalysis.py @@ -364,9 +364,9 @@ class Error(OWWidget.Error): # currently selected agent prominence metric agent_prominence_metric = constants.SELECTED_PROMINENCE_METRIC # minimum possible score for agent prominence - agent_prominence_score_min = 0.0 + agent_prominence_score_min = 0 # maximum possible score for agent prominence - agent_prominence_score_max = 15.0 + agent_prominence_score_max = 15 word_prominence_scores = {} @@ -834,13 +834,13 @@ def show_docs(self, slider_engaged=False): if feature.name.lower() == "content" or feature.name.lower() == "text": if len(self.story_elements_dict) > 0: value = self.actortagger.postag_text( - value, - self.nouns, - self.subjs, - self.custom, - self.agent_prominence_metric, - self.agent_prominence_score_min, - self.story_elements_dict[str(c_index)] + text=value, + nouns=self.nouns, + subjs=self.subjs, + custom=self.custom, + selected_prominence_metric=self.agent_prominence_metric, + prominence_score_min=self.agent_prominence_score_min, + story_elements_df=self.story_elements_dict[str(c_index)] ) if feature in self.search_features and (len(self.regexp_filter) > 0): diff --git a/orangecontrib/storynavigation/tests/__init__.py b/tests/__init__.py similarity index 100% rename from orangecontrib/storynavigation/tests/__init__.py rename to tests/__init__.py diff --git a/orangecontrib/storynavigation/tests/storynavigator-testdata.tab b/tests/storynavigator-testdata.tab similarity index 100% rename from orangecontrib/storynavigation/tests/storynavigator-testdata.tab rename to tests/storynavigator-testdata.tab diff --git a/orangecontrib/storynavigation/tests/storynavigator-testdata_quotes.tab b/tests/storynavigator-testdata_quotes.tab similarity index 100% rename from orangecontrib/storynavigation/tests/storynavigator-testdata_quotes.tab rename to tests/storynavigator-testdata_quotes.tab diff --git a/orangecontrib/storynavigation/tests/test_OWSNActorAnalysis.py b/tests/test_OWSNActorAnalysis.py similarity index 89% rename from orangecontrib/storynavigation/tests/test_OWSNActorAnalysis.py rename to tests/test_OWSNActorAnalysis.py index ac903ba..c300679 100644 --- a/orangecontrib/storynavigation/tests/test_OWSNActorAnalysis.py +++ b/tests/test_OWSNActorAnalysis.py @@ -1,5 +1,4 @@ import logging -import unittest import os from storynavigation.widgets.OWSNActorAnalysis import OWSNActorAnalysis @@ -37,7 +36,7 @@ def setUp(self): def load(self): self.logger.info("loading data...") self.widget.corpus = Corpus.from_file(os.path.join(self.current_dir, constants.TEST_DATA_FILE_NAME)) - self.send_signal(self.widget.Inputs.corpus, self.widget.corpus) + self.send_signal(self.widget.Inputs.stories, self.widget.corpus) self.logger.info("loading completed.") def test_tagging(self): @@ -61,13 +60,13 @@ def test_tagging(self): if len(value) > 0: value = self.actortagger.postag_text( - value, - True, - True, - False, - {}, - constants.SELECTED_PROMINENCE_METRIC, - 0.0 + text=value, + nouns=True, + subjs=True, + custom=False, + selected_prominence_metric=0, + prominence_score_min=constants.SELECTED_PROMINENCE_METRIC, + story_elements_df=None, ) self.tagging_completed = True @@ -89,6 +88,3 @@ def test_actor_metrics(self): self.logger.info("metrics calculated.") else: self.logger.info("metrics could not be calculated.") - -if __name__ == '__main__': - unittest.main() diff --git a/tox.ini b/tox.ini deleted file mode 100755 index 1fffa96..0000000 --- a/tox.ini +++ /dev/null @@ -1,38 +0,0 @@ -[tox] -; envlist = py39, python3.10, python3.11, orange-{latest, released} -envlist = python3.10, orange-latest -; envlist = py39, orange-{latest} -skip_missing_interpreters = true -isolated_build = true - -[testenv] -# must use latest pip (version 20.3.1 enables Big Sur support - https://github.com/pypa/pip/issues/9138) -pip_version = pip -extras = test -passenv = * -allowlist_externals = * -# we MUST changedir to avoid installed being shadowed by working dir -# https://github.com/tox-dev/tox/issues/54 -# https://github.com/tox-dev/tox/issues/514 -changedir = - ; {envsitepackagesdir} - {toxinidir} -setenv = - # Raise deprecations as errors in our tests - ORANGE_DEPRECATIONS_ERROR=y - # Need this otherwise unittest installs a warning filter that overrides - # our desire to have OrangeDeprecationWarnings raised - PYTHONWARNINGS=module - # set coverage output and project config - COVERAGE_FILE = {toxinidir}/.coverage - COVERAGE_RCFILE = {toxinidir}/.coveragerc -deps = - -r{toxinidir}/requirements_dev.txt - latest: pytest -commands = - # pytest - # ls /home/runner/work/orange-story-navigator/orange-story-navigator - coverage run -m unittest discover orangecontrib/storynavigation - # coverage run -m unittest discover orangecontrib/storynavigation - # coverage run -m pytest -v orangecontrib/storynavigation - # coverage report