diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..2197dc0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +tests/data/train_smoke/* filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 87f972c..975b38b 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -25,9 +25,9 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - fetch-depth: "0" + lfs: 'true' - name: Log in to the Container registry uses: docker/login-action@v2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 045c425..1aec4f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,9 @@ jobs: linting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 + with: + lfs: 'true' - name: Install Python uses: actions/setup-python@v2 @@ -47,7 +49,9 @@ jobs: sphinx-docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 + with: + lfs: 'true' - name: Install Python uses: actions/setup-python@v2 @@ -76,9 +80,9 @@ jobs: - '3.11' needs: linting steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: - fetch-depth: 0 # we need tags for versioneer to work + lfs: 'true' - name: Install Python uses: actions/setup-python@v2 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 4149e3d..84d2519 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -17,10 +17,10 @@ jobs: package-name: cada-prio token: ${{ secrets.BOT_TOKEN }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{ steps.release.outputs.release_created }} with: - fetch-depth: 0 + lfs: 'true' - name: Set up Python if: ${{ steps.release.outputs.release_created }} diff --git a/.gitignore b/.gitignore index 9996ce3..99e20a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/model-out + *~ .*.sw? diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d458142..8dbe42c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -16,7 +16,7 @@ Types of Contributions Report Bugs =========== -Report bugs at https://github.com/bihealth/cada-ng/issues. +Report bugs at https://github.com/bihealth/cada-prio/issues. If you are reporting a bug, please include: @@ -39,12 +39,12 @@ Anything tagged with "enhancement" and "help wanted" is open to whoever wants to Write Documentation =================== -cada-ng could always use more documentation, whether as part of the official cada-ng docs, in docstrings, or even on the web in blog posts, articles, and such. +cada-prio could always use more documentation, whether as part of the official cada-prio docs, in docstrings, or even on the web in blog posts, articles, and such. Submit Feedback =============== -The best way to send feedback is to file an issue at https://github.com/bihealth/cada-ng/issues. +The best way to send feedback is to file an issue at https://github.com/bihealth/cada-prio/issues. If you are proposing a feature: @@ -56,18 +56,18 @@ If you are proposing a feature: Get Started! ------------ -Ready to contribute? Here's how to set up `cada-ng` for local development. +Ready to contribute? Here's how to set up `cada-prio` for local development. -1. Fork the `cada-ng` repo on GitHub. +1. Fork the `cada-prio` repo on GitHub. 2. Clone your fork locally:: - $ git clone git@github.com:bihealth/cada-ng.git + $ git clone git@github.com:bihealth/cada-prio.git 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: - $ mkvirtualenv cada-ng - $ cd cada-ng/ + $ mkvirtualenv cada-prio + $ cd cada-prio/ $ python setup.py develop 4. Create a branch for local development:: @@ -79,7 +79,7 @@ Ready to contribute? Here's how to set up `cada-ng` for local development. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: - $ flake8 cada-ng tests + $ flake8 cada-prio tests $ python setup.py test or pytest $ tox diff --git a/README.md b/README.md index dde797d..928a71c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -[![CI](https://github.com/bihealth/cada-ng/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/bihealth/cada-ng/actions/workflows/main.yml) -[![codecov](https://codecov.io/gh/bihealth/cada-ng/graph/badge.svg?token=HIBwaG4eYM)](https://codecov.io/gh/bihealth/cada-ng) -[![Documentation Status](https://readthedocs.org/projects/cada-ng/badge/?version=latest)](https://cada-ng.readthedocs.io/en/latest/?badge=latest) -[![Pypi](https://img.shields.io/pypi/pyversions/cada-ng.svg)](https://pypi.org/project/cada-ng) +[![CI](https://github.com/bihealth/cada-prio/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/bihealth/cada-prio/actions/workflows/main.yml) +[![codecov](https://codecov.io/gh/bihealth/cada-prio/graph/badge.svg?token=HIBwaG4eYM)](https://codecov.io/gh/bihealth/cada-prio) +[![Documentation Status](https://readthedocs.org/projects/cada-prio/badge/?version=latest)](https://cada-prio.readthedocs.io/en/latest/?badge=latest) +[![Pypi](https://img.shields.io/pypi/pyversions/cada-prio.svg)](https://pypi.org/project/cada-prio) # CADA: The Next Generation This is a re-implementation of the [CADA](https://github.com/Chengyao-Peng/CADA) method for phenotype-similarity prioritization. - Free software: MIT license -- Documentation: https://cada-ng.readthedocs.io/en/latest/ -- Discussion Forum: https://github.com/bihealth/cada-ng/discussions -- Bug Reports: https://github.com/bihealth/cada-ng/issues +- Documentation: https://cada-prio.readthedocs.io/en/latest/ +- Discussion Forum: https://github.com/bihealth/cada-prio/discussions +- Bug Reports: https://github.com/bihealth/cada-prio/issues ## Managing GitHub Project with Terraform @@ -22,7 +22,7 @@ This is a re-implementation of the [CADA](https://github.com/Chengyao-Peng/CADA) # cd utils/terraform # terraform init -# terraform import github_repository.cada-ng cada-ng +# terraform import github_repository.cada-prio cada-prio # terraform validate # terraform fmt # terraform plan diff --git a/cada_prio/cli.py b/cada_prio/cli.py index 917ceb2..7c36191 100644 --- a/cada_prio/cli.py +++ b/cada_prio/cli.py @@ -2,7 +2,7 @@ import click -from cada_prio import _version +from cada_prio import _version, train_model @click.group() @@ -13,3 +13,31 @@ def cli(ctx: click.Context, verbose: bool): """Main entry point for CLI via click.""" ctx.ensure_object(dict) ctx.obj["verbose"] = verbose + + +@cli.command("train-model") +@click.argument("path_out", type=str) +@click.option("--path-hgnc-json", type=str, help="path to HGNC JSON", required=True) +@click.option( + "--path-gene-hpo-links", type=str, help="path to gene-HPO term links JSONL", required=True +) +@click.option( + "--path-hpo-genes-to-phenotype", + type=str, + help="path to genes_to_phenotype.txt file", + required=True, +) +@click.option("--path-hpo-obo", type=str, help="path HPO OBO file", required=True) +@click.pass_context +def cli_train_model( + ctx: click.Context, + path_out: str, + path_hgnc_json: str, + path_gene_hpo_links: str, + path_hpo_genes_to_phenotype: str, + path_hpo_obo: str, +): + ctx.ensure_object(dict) + train_model.run( + path_out, path_hgnc_json, path_gene_hpo_links, path_hpo_genes_to_phenotype, path_hpo_obo + ) diff --git a/cada_prio/train_model.py b/cada_prio/train_model.py new file mode 100644 index 0000000..048aab6 --- /dev/null +++ b/cada_prio/train_model.py @@ -0,0 +1,288 @@ +import csv +import enum +import itertools +import json +import os +import typing +import warnings + +import attrs +import cattrs +from logzero import logger +import networkx as nx +import node2vec +import pronto + + +@attrs.frozen(auto_attribs=True) +class GeneIds: + """Mapping between gene IDs""" + + symbol: str + hgnc_id: str + ncbi_gene_id: str + ensembl_gene_id: str + + +@enum.unique +class ClinSig(enum.Enum): + BENIGN = "benign" + LIKELY_BENIGN = "likely benign" + UNCERTAIN = "uncertain significance" + LIKELY_PATHOGENIC = "likely pathogenic" + PATHOGENIC = "pathogenic" + + +@attrs.frozen(auto_attribs=True) +class GenePhenotypeRecord: + """Full record from JSONL file""" + + #: RCV accession + rcv: str + #: SCV accession + scv: str + #: Clinical significance + clinsig: typing.Optional[ClinSig] + #: Submitter + submitter: typing.Optional[str] + #: Gene HGNC ID + hgnc_ids: typing.List[str] + #: Linked OMIM terms + omim_terms: typing.List[str] + #: Linked MONDO terms + mondo_terms: typing.List[str] + #: Linked HPO terms + hpo_terms: typing.List[str] + + +@attrs.frozen(auto_attribs=True, order=True) +class GeneToPhenotypeRecord: + """Minimal link record""" + + #: Submitter + submitter: str + #: Gene HGNC ID + hgnc_id: str + #: Linked HPO terms + hpo_terms: typing.Tuple[str, ...] + + +def load_gene_phenotype_records(path: str) -> typing.Iterable[GenePhenotypeRecord]: + with open(path) as f: + for line in f: + yield cattrs.structure(json.loads(line), GenePhenotypeRecord) + + +def load_hpo_ontology( + path_hpo_obo, +) -> typing.Tuple[pronto.Ontology, typing.Dict[str, str], typing.Dict[str, str]]: + logger.info("Loading HPO OBO from %s...", path_hpo_obo) + logger.info("- parsing ...") + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=UnicodeWarning) + hpo_ontology = pronto.Ontology(path_hpo_obo) + logger.info("- extracting term ids ...") + hpo_id_from_alt: typing.Dict[str, str] = {} + hpo_id_to_name: typing.Dict[str, str] = {} + for term in hpo_ontology.terms(): + if not term.name or not term.id: + continue + hpo_id_to_name[term.id] = term.name + for alternate_id in term.alternate_ids: + hpo_id_from_alt[alternate_id] = term.id + hpo_id_to_name[alternate_id] = term.name + logger.info("... done loading %s terms", len(hpo_ontology)) + + return hpo_ontology, hpo_id_from_alt, hpo_id_to_name + + +def load_hpo_gen2phen( + path_hpo_genes_to_phenotype: str, ncbi_to_hgnc: typing.Dict[str, str] +) -> typing.List[GeneToPhenotypeRecord]: + logger.info("Loading HPO gene-phenotype links from %s...", path_hpo_genes_to_phenotype) + logger.info("- parsing records ...") + warned_about = set() + with open(path_hpo_genes_to_phenotype, "rt") as inputf: + reader = csv.DictReader(inputf, delimiter="\t") + hpo_by_gene: typing.Dict[str, typing.Set[str]] = {} + for record in reader: + ncbi_gene_id = record["ncbi_gene_id"] + if ncbi_gene_id not in ncbi_to_hgnc: + if ncbi_gene_id not in warned_about: + logger.warning("No HGNC entry for Entrez %s found", ncbi_gene_id) + warned_about.add(ncbi_gene_id) + continue + hgnc_id = ncbi_to_hgnc[ncbi_gene_id] + hpo_by_gene.setdefault(hgnc_id, set()).add(record["hpo_id"]) + + hpo_gene_to_phenotype_set = { + GeneToPhenotypeRecord( + submitter="HPO", + hgnc_id=hgnc_id, + hpo_terms=tuple(hpo_terms), + ) + for hgnc_id, hpo_terms in hpo_by_gene.items() + } + logger.info("- sorting ...") + hpo_gene_to_phenotype = list(sorted(hpo_gene_to_phenotype_set)) + logger.info("... done loading %s records", len(hpo_gene_to_phenotype)) + + return hpo_gene_to_phenotype + + +def load_clinvar_gen2phen(path_gene_hpo_links: str) -> typing.List[GeneToPhenotypeRecord]: + logger.info("Loading ClinVar gene-phenotype links from %s...", path_gene_hpo_links) + logger.info("- parsing records ...") + clinvar_gene_to_phenotype_set = { + GeneToPhenotypeRecord( + submitter=record.submitter, + hgnc_id=record.hgnc_ids[0], + hpo_terms=tuple(record.hpo_terms), + ) + for record in load_gene_phenotype_records(path_gene_hpo_links) + if record.clinsig in (ClinSig.LIKELY_PATHOGENIC, ClinSig.PATHOGENIC) + and len(record.hgnc_ids) == 1 + and record.submitter + } + logger.info("- sorting ...") + clinvar_gene_to_phenotype = list(sorted(clinvar_gene_to_phenotype_set)) + logger.info("... done loading %s records", len(clinvar_gene_to_phenotype_set)) + + return clinvar_gene_to_phenotype + + +def load_hgnc_info(path_hgnc_json) -> typing.Tuple[typing.Dict[str, str], typing.List[GeneIds]]: + logger.info("Loading HGNC info from %s...", path_hgnc_json) + gene_ids = [] + ncbi_to_hgnc = {} + with open(path_hgnc_json) as f: + full_hgnc = json.load(f) + for doc in full_hgnc["response"]["docs"]: + if all(key in doc for key in ("symbol", "entrez_id")): + gene_id = GeneIds( + symbol=doc["symbol"], + hgnc_id=doc["hgnc_id"], + ncbi_gene_id=doc["entrez_id"], + ensembl_gene_id=doc.get("ensembl_gene_id"), + ) + ncbi_to_hgnc[gene_id.ncbi_gene_id] = gene_id.hgnc_id + gene_ids.append(gene_id) + logger.info("... done loading %s records", len(gene_ids)) + + return ncbi_to_hgnc, gene_ids + + +#: type alias for an edge. +Edge = typing.Tuple[str, str] + + +def yield_hpo_edges(hpo_ontology: pronto.Ontology) -> typing.Iterator[Edge]: + """Yield hierarchical edges from the HPO ontology""" + for term in hpo_ontology.terms(): + parents = list(term.superclasses(distance=1)) + for parent in parents[1:]: + yield (term.id, parent.id) + + +def yield_gene2phen_edges(links: typing.List[GeneToPhenotypeRecord]) -> typing.Iterator[Edge]: + """Yield edges from link record list""" + for link in links: + for hpo_term in link.hpo_terms: + yield (link.hgnc_id, hpo_term) + + +@attrs.frozen(auto_attribs=True) +class EmbeddingParams: + """Parameters for the embedding""" + + #: The number of dimensions of feature vectors + dimensions: int = 300 + #: The number of nodes in each random walk + walk_length: int = 60 + #: Controls the probability for a walk to visit immediately back to the previous node + p: float = 1.7987535798694703 + #: Controls the probability for a walk to visit previously unexplored neighborhoods in the + #: graph + q: float = 3.875406134463754 + #: Number of random walks to be generated from each node in the graph + num_walks: int = 10 + #: Limit on the number of words in each context + window: int = 4 + #: Set the min_count in the fitting + min_count: int = 1 + #: Set the batch_words in the fitting + batch_words: int = 4 + #: Number of workers threads to use + workers: int = 4 + + +def build_and_fit_model(clinvar_gen2phen, hpo_ontology): + # create graph edges combining HPO hierarchy and training edges from ClinVar + logger.info("Constructing training graph ...") + logger.info("- building edges ...") + training_edges = list( + itertools.chain(yield_hpo_edges(hpo_ontology), yield_gene2phen_edges(clinvar_gen2phen)) + ) + logger.info("- graph construction") + training_graph = nx.Graph() + training_graph.add_edges_from(training_edges) + logger.info("... done constructing training graph with %s edges", len(training_edges)) + + logger.info("Computing the embedding / model fit...") + logger.info("- embedding graph") + embedding_params = EmbeddingParams() + embedding = node2vec.Node2Vec( + training_graph, + dimensions=embedding_params.dimensions, + walk_length=embedding_params.walk_length, + num_walks=embedding_params.num_walks, + p=embedding_params.p, + q=embedding_params.q, + workers=embedding_params.workers, + ) + logger.info("- fitting model") + model = embedding.fit( + window=embedding_params.window, + min_count=embedding_params.min_count, + batch_words=embedding_params.batch_words, + ) + logger.info("... done computing the embedding") + return training_graph, model + + +def write_graph_and_model(path_out, training_graph, model): + os.makedirs(path_out, exist_ok=True) + + path_graph = os.path.join(path_out, "graph.gpickle") + logger.info("Saving graph to %s...", path_graph) + nx.write_gpickle(training_graph, path_graph) + logger.info("... done saving graph") + + logger.info("Saving embedding to %s...", path_out) + path_embeddings = os.path.join(path_out, "embedding") + logger.info("- %s", path_embeddings) + model.wv.save_word2vec_format(path_embeddings) + path_model = os.path.join(path_out, "model") + logger.info("- %s", path_model) + model.save(path_model) + logger.info("... done saving embedding to") + + +def run( + path_out: str, + path_hgnc_json: str, + path_gene_hpo_links: str, + path_hpo_genes_to_phenotype: str, + path_hpo_obo: str, +): + # load all data + ncbi_to_hgnc, hgnc_info = load_hgnc_info(path_hgnc_json) + clinvar_gen2phen = load_clinvar_gen2phen(path_gene_hpo_links) + hpo_gen2phen = load_hpo_gen2phen(path_hpo_genes_to_phenotype, ncbi_to_hgnc) + hpo_ontology, hpo_id_from_alt, hpo_id_to_name = load_hpo_ontology(path_hpo_obo) + _, _, _, _ = hgnc_info, hpo_gen2phen, hpo_id_from_alt, hpo_id_to_name + + # build and fit model + training_graph, model = build_and_fit_model(clinvar_gen2phen, hpo_ontology) + # write out graph and model + write_graph_and_model(path_out, training_graph, model) diff --git a/docs/installation.rst b/docs/installation.rst index 9bf5a51..c42d6bf 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -24,10 +24,10 @@ If you don't have `pip `__ installed, this `Python installa From Sources ------------ -The sources for CADA can be downloaded from the `Github repo `__. +The sources for CADA can be downloaded from the `Github repo `__. Clone the public repository: .. code-block:: console - $ git clone https://github.com/bihealth/cada-ng.git + $ git clone https://github.com/bihealth/cada-prio.git diff --git a/requirements/base.txt b/requirements/base.txt index c102d56..229cd9d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -4,3 +4,6 @@ cattrs >=22.2.0, <24.0 click >=8.1.3, <9.0 toml >=0.10.2, <0.11 tqdm >=4.0 +pronto >=2.5, <3.0 +networkx +node2vec >=0.4.6, <0.5 diff --git a/requirements/test.txt b/requirements/test.txt index 1b36e72..9f9023e 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -16,6 +16,7 @@ types-tabulate >=0.9.0.0 types-jsonschema >=4.17.0 types-tqdm >=4.66.0 types-xmltodict >=0.13.0.3 +networkx-stubs sphinx sphinx_rtd_theme diff --git a/setup.py b/setup.py index 5123b50..d32c6e9 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ def parse_requirements(path): ), test_suite="tests", tests_require=test_requirements, - url="https://github.com/bihealth/cada-ng", + url="https://github.com/bihealth/cada-prio", version=version, zip_safe=False, ) diff --git a/stubs/gensim/models.pyi b/stubs/gensim/models.pyi new file mode 100644 index 0000000..88d53c3 --- /dev/null +++ b/stubs/gensim/models.pyi @@ -0,0 +1,7 @@ +class KeyedVectors: + def save_word2vec_format(self, fname: str): ... + +class Word2Vec: + wv: KeyedVectors + + def save(self, fname: str): ... diff --git a/stubs/node2vec.pyi b/stubs/node2vec.pyi new file mode 100644 index 0000000..e32561b --- /dev/null +++ b/stubs/node2vec.pyi @@ -0,0 +1,24 @@ +import typing + +import gensim.models +import networkx as nx + +class Node2Vec: + def __init__( + self, + graph: nx.Graph, + dimensions: int = 128, + walk_length: int = 80, + num_walks: int = 10, + p: float = 1, + q: float = 1, + weight_key: str = "weight", + workers: int = 1, + sampling_strategy: typing.Optional[dict] = None, + quiet: bool = False, + temp_folder: typing.Optional[str] = None, + seed: typing.Optional[int] = None, + ): ... + def fit( + self, window: int, min_count: int, batch_words: int, **kwargs + ) -> gensim.models.Word2Vec: ... diff --git a/tests/data/train_smoke/genes_to_phenotype.txt b/tests/data/train_smoke/genes_to_phenotype.txt new file mode 100644 index 0000000..c03da33 --- /dev/null +++ b/tests/data/train_smoke/genes_to_phenotype.txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d17d73f47b10d9b7741140857341119ec7cb88dced051ea64a674d01bae81dd4 +size 18594201 diff --git a/tests/data/train_smoke/hgnc_complete_set_2023-09-01.json b/tests/data/train_smoke/hgnc_complete_set_2023-09-01.json new file mode 100644 index 0000000..0560993 --- /dev/null +++ b/tests/data/train_smoke/hgnc_complete_set_2023-09-01.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e56a3413f01ce7ba9b2d60f4765f4064ee4b8904ed850b7855f0503d2a7d4096 +size 34851645 diff --git a/tests/data/train_smoke/hp.obo b/tests/data/train_smoke/hp.obo new file mode 100644 index 0000000..6edaa1a --- /dev/null +++ b/tests/data/train_smoke/hp.obo @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04ece06aa74a17a74c1be2651a81f2201da88c0d19718f6302db703f8d8651b1 +size 9364837 diff --git a/tests/data/train_smoke/links.jsonl b/tests/data/train_smoke/links.jsonl new file mode 100644 index 0000000..cfed511 --- /dev/null +++ b/tests/data/train_smoke/links.jsonl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:045c4faee127a8cde81e8d25251a5595530cad2b6cb28122624b2deea6d1f164 +size 69157 diff --git a/tests/test_dummy.py b/tests/test_dummy.py deleted file mode 100644 index f4f5361..0000000 --- a/tests/test_dummy.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_dummy(): - assert True diff --git a/tests/test_train_model.py b/tests/test_train_model.py new file mode 100644 index 0000000..18e3181 --- /dev/null +++ b/tests/test_train_model.py @@ -0,0 +1,11 @@ +from cada_prio import train_model + + +def test_train_smoke_test(tmpdir): + train_model.run( + f"{tmpdir}/train_out", + "tests/data/train_smoke/hgnc_complete_set_2023-09-01.json", + "tests/data/train_smoke/links.jsonl", + "tests/data/train_smoke/genes_to_phenotype.txt", + "tests/data/train_smoke/hp.obo", + ) diff --git a/utils/docker/build-docker.sh b/utils/docker/build-docker.sh index 75b7cc5..5d26886 100755 --- a/utils/docker/build-docker.sh +++ b/utils/docker/build-docker.sh @@ -6,7 +6,7 @@ set -x set -euo pipefail ORG=bihealth -REPO=cada-ng +REPO=cada-prio DOCKER_VERSION=${DOCKER_VERSION-adhoc} sudo docker build . \ diff --git a/utils/terraform/main.tf b/utils/terraform/main.tf index f40eeb9..a36f677 100644 --- a/utils/terraform/main.tf +++ b/utils/terraform/main.tf @@ -1,7 +1,7 @@ # Mangement of the GitHub project. -resource "github_repository" "cada-ng" { - name = "cada-ng" +resource "github_repository" "cada-prio" { + name = "cada-prio" description = "Re-implementation of the CADA phenotype-based prioritization algorithm" has_issues = true