diff --git a/.github/workflows/conda-test.yml b/.github/workflows/conda-test.yml new file mode 100644 index 00000000..889c67c7 --- /dev/null +++ b/.github/workflows/conda-test.yml @@ -0,0 +1,44 @@ +name: Conda test + +on: + pull_request: + branches: + - master + workflow_dispatch: + schedule: + - cron: '0 0 1 * *' + + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + max-parallel: 5 + + steps: + - uses: actions/checkout@v3 + - name: setup miniconda + uses: conda-incubator/setup-miniconda@v2.2.0 + with: + environment-file: environment.yml + activate-environment: plannotate + + - name: get conda info + shell: bash -l {0} + run: | + conda info + conda list + + - name: get plannotate dbs + shell: bash -l {0} + run: | + python -c "from plannotate.resources import download_databases; download_databases()" + + - name: pytest + shell: bash -l {0} + run: | + pip install pytest + pytest --version + pytest diff --git a/.github/workflows/python-package-conda.yml b/.github/workflows/python-package-conda.yml index 3a011945..ec15e4a7 100644 --- a/.github/workflows/python-package-conda.yml +++ b/.github/workflows/python-package-conda.yml @@ -21,11 +21,14 @@ jobs: generate-run-shell: true environment-file: environment.yml cache-downloads: true + - run: pip install pytest shell: micromamba-shell {0} + - run: | python -c "from plannotate.resources import download_databases; download_databases()" shell: micromamba-shell {0} + - run: | pytest --version pytest diff --git a/.streamlit/config.toml b/.streamlit/config.toml index 3fff6dcf..8ce9b2a0 100644 --- a/.streamlit/config.toml +++ b/.streamlit/config.toml @@ -147,38 +147,3 @@ showfileUploaderEncoding = "True" # Default: "True" showPyplotGlobalUse = "True" - -[s3] - -# Name of the AWS S3 bucket to save apps. -# Default: (unset) -#bucket = - -# URL root for external view of Streamlit apps. -# Default: (unset) -#url = - -# Access key to write to the S3 bucket. -# Leave unset if you want to use an AWS profile. -# Default: (unset) -#accessKeyId = - -# Secret access key to write to the S3 bucket. -# Leave unset if you want to use an AWS profile. -# Default: (unset) -#secretAccessKey = - -# The "subdirectory" within the S3 bucket where to save apps. -# S3 calls paths "keys" which is why the keyPrefix is like a subdirectory. Use "" to mean the root directory. -# Default: "" -keyPrefix = "" - -# AWS region where the bucket is located, e.g. "us-west-2". -# Default: (unset) -#region = - -# AWS credentials profile to use. -# Leave unset to use your default profile. -# Default: (unset) -#profile = - diff --git a/environment.yml b/environment.yml index b3714244..4b7bbfcf 100644 --- a/environment.yml +++ b/environment.yml @@ -15,6 +15,6 @@ dependencies: - ripgrep>=13.0.0 - tabulate>=0.8.9 - trnascan-se>=2.0.7 - - streamlit=1.8.* + - streamlit=1.8.1 - altair=4.2.* - bokeh=2.4.1 diff --git a/plannotate/annotate.py b/plannotate/annotate.py index c395ea47..1b9599dc 100644 --- a/plannotate/annotate.py +++ b/plannotate/annotate.py @@ -200,7 +200,7 @@ def clean(inDf): columnSlice = list(range(0, qend + 1)) + list(range(qstart, end)) # only the rows that are in the columns of hit - rowSlice = (seqSpace[columnSlice] == kind).any(axis = 1) + rowSlice = (seqSpace[columnSlice] == kind).any(axis=1) toDrop = toDrop | set( seqSpace[rowSlice].loc[i + 1 :].index ) # add the indexs below the current to the drop-set @@ -306,7 +306,19 @@ def calc_priority_mod(d, s, e): return feat_desc -@st.cache( +def cache(*args, **kwargs): + def decorator(func): + try: + __IPYTHON__ # type: ignore + # We are in a Jupyter environment, so don't apply st.cache + return func + except NameError: + return st.cache(func, *args, **kwargs) + + return decorator + + +@cache( hash_funcs={pd.DataFrame: lambda _: None}, suppress_st_warning=True, max_entries=10, diff --git a/plannotate/bokeh_plot.py b/plannotate/bokeh_plot.py index e61ab580..f8ea5003 100644 --- a/plannotate/bokeh_plot.py +++ b/plannotate/bokeh_plot.py @@ -152,7 +152,6 @@ def calc_level(inDf): ) calculated_levels = pd.DataFrame(columns=["index", "s", "e", "level"]) - # calculated_levels = [pd.DataFrame(columns=["index", "s", "e", "level"])] for index in levels.index: s = levels.loc[index]["qstart"] e = levels.loc[index]["qend"] @@ -183,6 +182,8 @@ def calc_level(inDf): ), ] ) + + calculated_levels = calculated_levels.set_index("index") inDf = inDf.join(calculated_levels[["level"]]) ################################################################ diff --git a/plannotate/data/data/databases.yml b/plannotate/data/data/databases.yml index 8249f33b..c12cf5a6 100644 --- a/plannotate/data/data/databases.yml +++ b/plannotate/data/data/databases.yml @@ -22,6 +22,10 @@ fpbase: - --gapextend 1 - --algo ctg - --id 75 + - --max-hsps 10 + - --culling-overlap 200 + - --seed-cut .001 + - --comp-based-stats 0 details: default_type: CDS location: Default @@ -40,6 +44,10 @@ swissprot: - --gapextend 1 - --algo ctg - --id 50 + - --max-hsps 10 + - --culling-overlap 200 + - --seed-cut .001 + - --comp-based-stats 0 details: default_type: CDS location: Default diff --git a/plannotate/pLannotate.py b/plannotate/pLannotate.py index 52e556d1..6d08e50b 100755 --- a/plannotate/pLannotate.py +++ b/plannotate/pLannotate.py @@ -97,6 +97,7 @@ def main_setupdb(): @click.option( "--input", "-i", + required=True, help=f"location of a FASTA or GBK file", ) @click.option( diff --git a/tests/manual_jupyter_test.ipynb b/tests/manual_jupyter_test.ipynb new file mode 100644 index 00000000..4ac68dd7 --- /dev/null +++ b/tests/manual_jupyter_test.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from plannotate.annotate import annotate\n", + "from plannotate.bokeh_plot import get_bokeh\n", + "from plannotate.resources import get_seq_record\n", + "from bokeh.io import show\n", + "\n", + "# for inline plotting in jupyter\n", + "from bokeh.resources import INLINE\n", + "import bokeh.io\n", + "bokeh.io.output_notebook(INLINE)\n", + "\n", + "seq = \"tgaccaggcatcaaataaaacgaaaggctcagtcgaaagactgggcctttcgttttatctgttgtttgtcggtgaacgctctctactagagtcacactggctcaccttcgggtgggcctttctgcgtttataggtctcaatccacgggtacgggtatggagaaacagtagagagttgcgataaaaagcgtcaggtagtatccgctaatcttatggataaaaatgctatggcatagcaaagtgtgacgccgtgcaaataatcaatgtggacttttctgccgtgattatagacacttttgttacgcgtttttgtcatggctttggtcccgctttgttacagaatgcttttaataagcggggttaccggtttggttagcgagaagagccagtaaaagacgcagtgacggcaatgtctgatgcaatatggacaattggtttcttgtaatcgttaatccgcaaataacgtaaaaacccgcttcggcgggtttttttatggggggagtttagggaaagagcatttgtcatttgtttatttttctaaatacattcaaatatgtatccgctcatgagacaataaccctgataaatgcttcaataatattgaaaaaggaagagtatgagtattcaacatttccgtgtcgcccttattcccttttttgcgg\"\n", + "\n", + "# get pandas df of annotations\n", + "hits = annotate(seq, is_detailed = True, linear= True)\n", + "\n", + "# get biopython SeqRecord object\n", + "seq_record = get_seq_record(hits, seq)\n", + "\n", + "# show plot\n", + "show(get_bokeh(hits, linear=True))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tests/test_units.py b/tests/test_units.py index 2ef54491..ebd98978 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -7,8 +7,10 @@ import pytest from Bio import SeqIO from Bio.SeqRecord import SeqRecord +from click.testing import CliRunner from plannotate import annotate, bokeh_plot, resources, streamlit_app +from plannotate.pLannotate import main_streamlit, main_batch with open("./tests/test_data/RRNB_fragment.txt") as f: RRNB = f.read() @@ -149,10 +151,30 @@ def test_streamlit_app(): """this component is hard to test""" streamlit_app.run_streamlit(["--yaml-file", resources.get_yaml_path()]) +# # runs indefinitely +# def test_streamlit(): +# runner = CliRunner() +# result = runner.invoke(main_streamlit) +# assert result.exit_code == 0 + + +def test_batch(): + runner = CliRunner() + result = runner.invoke(main_batch) + assert result.exit_code == 2 # proper exit code for no args + + +def test_batch_help(): + runner = CliRunner() + result = runner.invoke(main_batch, ["--help"]) + assert result.exit_code == 0 + def test_annotate(): hits = annotate.annotate(RRNB) assert hits.iloc[0]["sseqid"] == "rrnB_T1_terminator" + hits = annotate.annotate(RRNB, linear=True) + assert hits.iloc[0]["sseqid"] == "rrnB_T1_terminator" ####