diff --git a/.gitignore b/.gitignore index 10b8ed009f612a591db3a79bb821422c6e2d82aa..a236b71aebc2c3ae5f482ce0b571692103cb31b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vscode *.code-workspace *.pyc -dist \ No newline at end of file +dist +*.egg-info \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..afc687e34045f75c7b7448837721e98b3b56ed4c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,24 @@ +image: python:3.7 + +stages: + - test + - deploy + +before_script: + - pip install poetry + - poetry install -v + +test: + stage: test + script: + - poetry run pytest + +deploy: + stage: deploy + script: + - poetry config http-basic.pypi $PYPI_USERNAME $PYPI_PWD + - poetry build -v + - poetry publish + + rules: + - if: '$CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/' diff --git a/README.md b/README.md index 6d59701aedbb8a8eb543a4c32fa5f7e8f02c1383..4441a6392fa820cb9065f718b2ba1c40fc6129a8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,37 @@ # CRISPRbact -Tools to design and analyse CRISPRi experiments +**Tools to design and analyse CRISPRi experiments in bacteria.** -## API +CRISPRbact currently contains an on-target activity prediction tool for the Streptococcus pyogenes dCas9 protein. +This tool takes as an input the sequence of a gene of interest and returns a list of possible target sequences with the predicted on-target activity. Predictions are made using a linear model fitted on data from a genome-wide CRISPRi screen performed in E. coli (Cui et al. Nature Communications, 2018). The model predicts the ability of dCas9 to block the RNA polymerase when targeting the non-template strand (i.e. the coding strand) of a target gene. + +## Getting Started + +### Installation + +For the moment, you can install this package only via PyPI + +#### PyPI + +```console +$ pip install crisprbact +$ crisprbact --help +``` + +``` +Usage: crisprbact [OPTIONS] COMMAND [ARGS]... + +Options: + -v, --verbose + --help Show this message and exit. + +Commands: + predict +``` + +### API + +Using this library in your python code. ```python from crisprbact import on_target_predict @@ -14,7 +43,7 @@ for guide_rna in guide_rnas: ``` -outputs : +_output :_ ``` {'target': 'TCATCACGGGCCTTCGCCACGCGCG', 'guide': 'TCATCACGGGCCTTCGCCAC', 'start': 82, 'stop': 102, 'pam': 80, 'ori': '-', 'pred': -0.4719254873780802} @@ -23,9 +52,15 @@ outputs : {'target': 'CCTGATCGGTATTGAACAGCATCTG', 'guide': 'CCTGATCGGTATTGAACAGC', 'start': 29, 'stop': 49, 'pam': 27, 'ori': '-', 'pred': 0.23853258873311955} ``` -## Command-line +### Command line interface + +#### Predict guide RNAs activity -### predict guide RNAs activity +Input the sequence of a target gene and this script will output candidate guide RNAs for the S. pyogenes dCas9 with predicted on-target activity. + +```console +$ crisprbact predict --help +``` ``` Usage: crisprbact predict [OPTIONS] COMMAND [ARGS]... @@ -38,32 +73,55 @@ Commands: from-str Outputs candidate guide RNAs for the S. ``` -#### From a string sequence: +##### From a string sequence: + +The target input sequence can be a simple string. + +```console +$ crisprbact predict from-str --help +``` + ``` Usage: crisprbact predict from-str [OPTIONS] [OUTPUT_FILE] Outputs candidate guide RNAs for the S. pyogenes dCas9 with predicted on- target activity from a target gene. - [OUTPUT_FILE] file where the precitions are saved. Default = "stdout" + [OUTPUT_FILE] file where the candidate guide RNAs are saved. Default = + "stdout" Options: -t, --target TEXT [required] --help Show this message and exit. ``` +```console +$ crisprbact predict from-str -t ACCACTGGCGTGCGCGTTACTCATCAGATGCTGTTCAATACCGATCAGGTTATCGAAGTGTTTGTGATTGTTTGCCGCGCGCGTGGCGAAGGCCCGTGATGAAGGAAAAGTTTTGCGCTATGTTGGCAATATTGATGAAG guide-rnas.tsv +``` + +output file `guide-rnas.tsv` : + +No `seq_id` is defined since it is from a simple string. ``` -crisprbact predict from-str -t ACCACTGGCGTGCGCGTTACTCATCAGATGCTGTTCAATACCGATCAGGTTATCGAAGTGTTTGTGATTGTTTGCCGCGCGCGTGGCGAAGGCCCGTGATGAAGGAAAAGTTTTGCGCTATGTTGGCAATATTGATGAAG guide-rnas.tsv +target PAM position prediction seq_id +TCATCACGGGCCTTCGCCACGCGCG 80 -0.4719254873780802 N/A +CATCACGGGCCTTCGCCACGCGCGC 79 1.0491308060379676 N/A +CGCGCGCGGCAAACAATCACAAACA 61 -0.9021152826078697 N/A +CCTGATCGGTATTGAACAGCATCTG 27 0.23853258873311955 N/A ``` -You can pipe the results : +You can also pipe the results : -``` -crisprbact predict from-str -t ACCACTGGCGTGCGCGTTACTCATCAGATGCTGTTCAATACCGATCAGGTTATCGAAGTGTTTGTGATTGTTTGCCGCGCGCGTGGCGAAGGCCCGTGATGAAGGAAAAGTTTTGCGCTATGTTGGCAATATTGATGAAG | tail -n +2 | wc -l +```console +$ crisprbact predict from-str -t ACCACTGGCGTGCGCGTTACTCATCAGATGCTGTTCAATACCGATCAGGTTATCGAAGTGTTTGTGATTGTTTGCCGCGCGCGTGGCGAAGGCCCGTGATGAAGGAAAAGTTTTGCGCTATGTTGGCAATATTGATGAAG | tail -n +2 | wc -l ``` -#### From a sequence file +##### From a sequence file + +```console +$ crisprbact predict from-seq --help +``` ``` Usage: crisprbact predict from-seq [OPTIONS] [OUTPUT_FILE] @@ -71,28 +129,29 @@ Usage: crisprbact predict from-seq [OPTIONS] [OUTPUT_FILE] Outputs candidate guide RNAs for the S. pyogenes dCas9 with predicted on- target activity from a target gene. - [OUTPUT_FILE] file where the precitions are saved. Default = "stdout" + [OUTPUT_FILE] file where the candidate guide RNAs are saved. Default = + "stdout" Options: - -t, --target FILENAME Sequence file [required] - -f, --seq-format TEXT Sequence file format - --help Show this message and exit. - + -t, --target FILENAME Sequence file [required] + -f, --seq-format [fasta|fa|gb|genbank] + Sequence file format [default: fasta] + --help Show this message and exit. ``` -- Fasta file (could be multifasta) +- Fasta file (could be a multifasta file) -``` -poetry run crisprbact predict from-seq -t /tmp/seq.fasta guide-rnas.tsv +```console +$ crisprbact predict from-seq -t /tmp/seq.fasta guide-rnas.tsv ``` - GenBank file -``` -poetry run crisprbact predict from-seq -t /tmp/seq.gb -f gb guide-rnas.tsv +```console +$ crisprbact predict from-seq -t /tmp/seq.gb -f gb guide-rnas.tsv ``` -### Output file +##### Output file ``` target PAM position prediction input_id diff --git a/crisprbact/cli.py b/crisprbact/cli.py index f459d35bb594344e280f2dfa15b129fef98335ed..e89b02c2e80fe006ff08c958e3bd3cbf20609f85 100644 --- a/crisprbact/cli.py +++ b/crisprbact/cli.py @@ -1,7 +1,6 @@ -import click from crisprbact import on_target_predict -from pathlib import Path from Bio import SeqIO +import click class Config(object): @@ -11,6 +10,8 @@ class Config(object): pass_config = click.make_pass_decorator(Config, ensure=True) +HEADER = ["target", "PAM position", "prediction", "seq_id"] + @click.group() @click.option("-v", "--verbose", is_flag=True) @@ -31,19 +32,17 @@ def predict(config): @pass_config def from_str(config, target, output_file): """ - Outputs candidate guide RNAs for the S. pyogenes dCas9 with predicted on-target activity from a target gene. + Outputs candidate guide RNAs for the S. pyogenes dCas9 with predicted on-target + activity from a target gene. - [OUTPUT_FILE] file where the precitions are saved. Default = "stdout" + [OUTPUT_FILE] file where the candidate guide RNAs are saved. Default = "stdout" """ if config.verbose: print_parameters(target) guide_rnas = on_target_predict(target) - click.echo( - "\t".join(["target", "PAM position", "prediction", "input_id"]), - file=output_file, - ) + click.echo("\t".join(HEADER), file=output_file) write_guide_rnas(guide_rnas, output_file) @@ -51,24 +50,28 @@ def from_str(config, target, output_file): @click.option( "-t", "--target", type=click.File("rU"), required=True, help="Sequence file" ) -@click.option("-f", "--seq-format", help="Sequence file format", default="fasta") +@click.option( + "-f", + "--seq-format", + type=click.Choice(["fasta", "fa", "gb", "genbank"]), + help="Sequence file format", + default="fasta", + show_default=True, +) @click.argument("output-file", type=click.File("w"), default="-") @pass_config def from_seq(config, target, seq_format, output_file): """ - Outputs candidate guide RNAs for the S. pyogenes dCas9 with predicted on-target activity from a target gene. + Outputs candidate guide RNAs for the S. pyogenes dCas9 with predicted on-target + activity from a target gene. - [OUTPUT_FILE] file where the precitions are saved. Default = "stdout" + [OUTPUT_FILE] file where the candidate guide RNAs are saved. Default = "stdout" """ fg = "blue" if config.verbose: print_parameters(target.name, fg) - # with open(target, "rU") as handle: - click.echo( - "\t".join(["target", "PAM position", "prediction", "input_id"]), - file=output_file, - ) + click.echo("\t".join(HEADER), file=output_file) for record in SeqIO.parse(target, seq_format): if config.verbose: click.secho(" - search guide RNAs for %s " % record.id, fg=fg) @@ -81,7 +84,7 @@ def print_parameters(target, fg="blue"): click.secho("Target sequence : %s" % target, fg=fg) -def write_guide_rnas(guide_rnas, output_file, input_id="N/A"): +def write_guide_rnas(guide_rnas, output_file, seq_id="N/A"): for guide_rna in guide_rnas: # click.echo(guide_rna) @@ -91,7 +94,7 @@ def write_guide_rnas(guide_rnas, output_file, input_id="N/A"): guide_rna["target"], str(guide_rna["pam"]), str(guide_rna["pred"]), - input_id, + seq_id, ] ), file=output_file, diff --git a/crisprbact/predict.py b/crisprbact/predict.py index 62bfb6e529e37a4ae1c5571a4691892bd98353f3..70b41df5d3e55888e410ac0604f7de71f9761870 100644 --- a/crisprbact/predict.py +++ b/crisprbact/predict.py @@ -1,6 +1,4 @@ import numpy as np -import gffpandas.gffpandas as gffpd -from typing import Tuple import re from importlib.resources import open_binary @@ -45,7 +43,7 @@ def find_targets(seq): ) -def on_target_predict(seq: str): +def on_target_predict(seq): seq = seq.upper() # make uppercase seq = re.sub(r"\s", "", seq) # removes white space diff --git a/poetry.lock b/poetry.lock index b30eb9be4354a421a954c62c7f42b2886df1016d..e8c17839fa2970f0ed37274b3c1ee2595c850c78 100644 --- a/poetry.lock +++ b/poetry.lock @@ -86,19 +86,6 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.5.0,<2.6.0" pyflakes = ">=2.1.0,<2.2.0" -[[package]] -category = "main" -description = "GFF annotations in panda data frames" -name = "gffpandas" -optional = false -python-versions = "*" -version = "1.2.0" - -[package.source] -reference = "eec669c257b47bb9300cc3a6ea022b2e5c398fc1" -type = "git" -url = "git://github.com/foerstner-lab/gffpandas.git" - [[package]] category = "dev" description = "Read metadata from Python packages" @@ -147,19 +134,6 @@ version = "19.2" pyparsing = ">=2.0.2" six = "*" -[[package]] -category = "main" -description = "Powerful data structures for data analysis, time series, and statistics" -name = "pandas" -optional = false -python-versions = ">=3.5.3" -version = "0.25.3" - -[package.dependencies] -numpy = ">=1.13.3" -python-dateutil = ">=2.6.1" -pytz = ">=2017.2" - [[package]] category = "dev" description = "plugin and hook calling mechanisms for python" @@ -228,26 +202,7 @@ python = "<3.8" version = ">=0.12" [[package]] -category = "main" -description = "Extensions to the standard Python datetime module" -name = "python-dateutil" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -version = "2.8.1" - -[package.dependencies] -six = ">=1.5" - -[[package]] -category = "main" -description = "World timezone definitions, modern and historical" -name = "pytz" -optional = false -python-versions = "*" -version = "2019.3" - -[[package]] -category = "main" +category = "dev" description = "Python 2 and 3 compatibility utilities" name = "six" optional = false @@ -262,14 +217,6 @@ optional = false python-versions = "*" version = "0.10.0" -[[package]] -category = "main" -description = "Type Hints for Python" -name = "typing" -optional = false -python-versions = "*" -version = "3.7.4.1" - [[package]] category = "dev" description = "Measures number of Terminal column cells of wide-character codes" @@ -291,7 +238,7 @@ version = "0.6.0" more-itertools = "*" [metadata] -content-hash = "7a100d866370199deb75fce33b39f74e30c872f864b944d6337acc44b92f7bf8" +content-hash = "7eec960df30c85f429e73f79ba022f4281ea60e9053334c56da04bde9b7bf317" python-versions = "^3.7" [metadata.hashes] @@ -304,23 +251,18 @@ click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] flake8 = ["45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb", "49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"] -gffpandas = [] importlib-metadata = ["aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", "d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"] mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"] numpy = ["0a7a1dd123aecc9f0076934288ceed7fd9a81ba3919f11a855a7887cbe82a02f", "0c0763787133dfeec19904c22c7e358b231c87ba3206b211652f8cbe1241deb6", "3d52298d0be333583739f1aec9026f3b09fdfe3ddf7c7028cb16d9d2af1cca7e", "43bb4b70585f1c2d153e45323a886839f98af8bfa810f7014b20be714c37c447", "475963c5b9e116c38ad7347e154e5651d05a2286d86455671f5b1eebba5feb76", "64874913367f18eb3013b16123c9fed113962e75d809fca5b78ebfbb73ed93ba", "683828e50c339fc9e68720396f2de14253992c495fdddef77a1e17de55f1decc", "6ca4000c4a6f95a78c33c7dadbb9495c10880be9c89316aa536eac359ab820ae", "75fd817b7061f6378e4659dd792c84c0b60533e867f83e0d1e52d5d8e53df88c", "7d81d784bdbed30137aca242ab307f3e65c8d93f4c7b7d8f322110b2e90177f9", "8d0af8d3664f142414fd5b15cabfd3b6cc3ef242a3c7a7493257025be5a6955f", "9679831005fb16c6df3dd35d17aa31dc0d4d7573d84f0b44cc481490a65c7725", "a8f67ebfae9f575d85fa859b54d3bdecaeece74e3274b0b5c5f804d7ca789fe1", "acbf5c52db4adb366c064d0b7c7899e3e778d89db585feadd23b06b587d64761", "ada4805ed51f5bcaa3a06d3dd94939351869c095e30a2b54264f5a5004b52170", "c7354e8f0eca5c110b7e978034cd86ed98a7a5ffcf69ca97535445a595e07b8e", "e2e9d8c87120ba2c591f60e32736b82b67f72c37ba88a4c23c81b5b8fa49c018", "e467c57121fe1b78a8f68dd9255fbb3bb3f4f7547c6b9e109f31d14569f490c3", "ede47b98de79565fcd7f2decb475e2dcc85ee4097743e551fe26cfc7eb3ff143", "f58913e9227400f1395c7b800503ebfdb0772f1c33ff8cb4d6451c06cabdf316", "fe39f5fd4103ec4ca3cb8600b19216cd1ff316b4990f4c0b6057ad982c0a34d5"] packaging = ["28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", "d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"] -pandas = ["00dff3a8e337f5ed7ad295d98a31821d3d0fe7792da82d78d7fd79b89c03ea9d", "22361b1597c8c2ffd697aa9bf85423afa9e1fcfa6b1ea821054a244d5f24d75e", "255920e63850dc512ce356233081098554d641ba99c3767dde9e9f35630f994b", "26382aab9c119735908d94d2c5c08020a4a0a82969b7e5eefb92f902b3b30ad7", "33970f4cacdd9a0ddb8f21e151bfb9f178afb7c36eb7c25b9094c02876f385c2", "4545467a637e0e1393f7d05d61dace89689ad6d6f66f267f86fff737b702cce9", "52da74df8a9c9a103af0a72c9d5fdc8e0183a90884278db7f386b5692a2220a4", "61741f5aeb252f39c3031d11405305b6d10ce663c53bc3112705d7ad66c013d0", "6a3ac2c87e4e32a969921d1428525f09462770c349147aa8e9ab95f88c71ec71", "7458c48e3d15b8aaa7d575be60e1e4dd70348efcd9376656b72fecd55c59a4c3", "78bf638993219311377ce9836b3dc05f627a666d0dbc8cec37c0ff3c9ada673b", "8153705d6545fd9eb6dd2bc79301bff08825d2e2f716d5dced48daafc2d0b81f", "975c461accd14e89d71772e89108a050fa824c0b87a67d34cedf245f6681fc17", "9962957a27bfb70ab64103d0a7b42fa59c642fb4ed4cb75d0227b7bb9228535d", "adc3d3a3f9e59a38d923e90e20c4922fc62d1e5a03d083440468c6d8f3f1ae0a", "bbe3eb765a0b1e578833d243e2814b60c825b7fdbf4cdfe8e8aae8a08ed56ecf", "df8864824b1fe488cf778c3650ee59c3a0d8f42e53707de167ba6b4f7d35f133", "e45055c30a608076e31a9fcd780a956ed3b1fa20db61561b8d88b79259f526f7", "ee50c2142cdcf41995655d499a157d0a812fce55c97d9aad13bc1eef837ed36c"] pluggy = ["0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", "fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"] py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] pyparsing = ["20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f", "4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a"] pytest = ["27abc3fef618a01bebb1f0d6d303d2816a99aa87a5968ebc32fe971be91eb1e6", "58cee9e09242937e136dbb3dab466116ba20d6b7828c7620f23947f37eb4dae4"] -python-dateutil = ["73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", "75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"] -pytz = ["1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", "b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"] six = ["1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", "30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"] toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] -typing = ["91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23", "c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36", "f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"] wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] zipp = ["3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", "f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"] diff --git a/pyproject.toml b/pyproject.toml index 175921e4178fb69a4947ef9c1be7502f2147b2bd..8c203e8113b8db5c5cd893f595a3bf0eddd2e242 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,26 @@ [tool.poetry] name = "crisprbact" version = "0.1.0" -description = "" +license = "GPL-3.0" +description = "Tools to design and analyse CRISPRi experiments" authors = ["David Bikard <david.bikard@pasteur.fr>", "Remi Planel <rplanel@pasteur.fr>"] +keywords = ["CRISPR", "genomics", "bacteria", "CRISPRi", "screen"] +homepage = "https://gitlab.pasteur.fr/dbikard/crisprbact" +classifiers = [ + "Environment :: Console", + "Operating System :: POSIX :: Linux", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Topic :: Scientific/Engineering :: Bio-Informatics", + "Natural Language :: English", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)" +] +readme = "README.md" [tool.poetry.dependencies] python = "^3.7" numpy = "^1.17" -pandas = "^0.25.3" -gffpandas = {git = "git://github.com/foerstner-lab/gffpandas.git"} click = "^7.0" -typing = "^3.7" biopython = "^1.75" [tool.poetry.dev-dependencies]