-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #75 from sudlab/ns-rse/66-parser
- Loading branch information
Showing
3 changed files
with
261 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
"""Functions for Processing.""" | ||
|
||
import argparse as arg | ||
import sys | ||
from pathlib import Path | ||
from typing import Any | ||
|
||
# from isoslam import __version__ | ||
|
||
|
||
def create_parser() -> arg.ArgumentParser: | ||
""" | ||
Create a parser for reading options. | ||
Parser is created with multiple sub-parsers for eading options to run ``isoslam``. | ||
Returns | ||
------- | ||
arg.ArgumentParser | ||
Argument parser. | ||
""" | ||
parser = arg.ArgumentParser( | ||
description="Run various programs related to IsoSLAM. Add the name of the program you wish to run." | ||
) | ||
parser.add_argument( | ||
"--version", | ||
# version=f"Installed version of IsoSlam : {__version__}", | ||
help="Report the installed version of IsoSLAM.", | ||
) | ||
parser.add_argument( | ||
"-c", | ||
"--config-file", | ||
dest="config_file", | ||
type=Path, | ||
required=False, | ||
help="Path to a YAML configuration file.", | ||
) | ||
parser.add_argument( | ||
"-o", | ||
"--output-dir", | ||
dest="output_dir", | ||
type=Path, | ||
required=False, | ||
help="Output directory to write results to.", | ||
) | ||
parser.add_argument( | ||
"-l", | ||
"--log-level", | ||
dest="log_level", | ||
type=str, | ||
required=False, | ||
help="Logging level to use, default is 'info' for verbose output use 'debug'.", | ||
) | ||
|
||
subparsers = parser.add_subparsers(title="program", description="Available programs listed below:", dest="program") | ||
|
||
# Create sub-parsers for different stages | ||
process_parser = subparsers.add_parser( | ||
"process", | ||
description="Process all files and run all summary plotting and statistics.", | ||
help="Process all files and run all summary plotting and statistics.", | ||
) | ||
process_parser.add_argument( | ||
"-b", | ||
"--bam-file", | ||
dest="bam_file", | ||
type=Path, | ||
required=False, | ||
help="Path to '.bam' file that has undergone read assignment with 'featureCount'.", | ||
) | ||
process_parser.add_argument( | ||
"-g", "--gtf-file", dest="gtf_file", type=Path, required=False, help="Path to '.gtf' transcript assembly file." | ||
) | ||
process_parser.add_argument( | ||
"-d", | ||
"--bed-file", | ||
dest="bed_file", | ||
type=Path, | ||
required=False, | ||
help="Path to '.bed' utron file. Must be bed6 format.", | ||
) | ||
process_parser.add_argument( | ||
"-v", "--vcf-file", dest="vcf_file", type=Path, required=False, help="Path to '.vcf.gz' file." | ||
) | ||
process_parser.set_defaults(func=process) | ||
# Additional parsers for future functionality | ||
# summarize_counts_parser = subparsers.add_parser( | ||
# "summarize", | ||
# description="Summarize counts.", | ||
# help="Summarize counts.", | ||
# ) | ||
# summarize_counts_parser.set_defaults(func=summarize_counts) | ||
# plot_conversions_parser = subparsers.add_parser( | ||
# "plot_conversions", | ||
# description="Plot conversions.", | ||
# help="Plot conversions.", | ||
# ) | ||
# plot_conversions_parser.set_defaults(func=plot_conversions) | ||
return parser | ||
|
||
|
||
def process(args: arg.Namespace | None) -> None: | ||
""" | ||
Process a set of files. | ||
Parameters | ||
---------- | ||
args : arg.Namespace | None | ||
Arguments function was invoked with. | ||
Returns | ||
------- | ||
None | ||
Function does not return anything. | ||
""" | ||
return | ||
|
||
|
||
def entry_point(manually_provided_args: list[Any] | None = None, testing: bool = False) -> None | arg.Namespace: | ||
""" | ||
Entry point for all IsoSLAM programs. | ||
Main entry point for running 'isoslam' which allows the different processing, plotting and testing modules to be | ||
run. | ||
Parameters | ||
---------- | ||
manually_provided_args : None | ||
Manually provided arguments. | ||
testing : bool | ||
Whether testing is being carried out. | ||
Returns | ||
------- | ||
None | ||
Function does not return anything. | ||
""" | ||
parser = create_parser() | ||
args = parser.parse_args() if manually_provided_args is None else parser.parse_args(manually_provided_args) | ||
|
||
# If no module has been specified print help and exit | ||
print(f"{args.program=}") | ||
if not args.program: | ||
parser.print_help() | ||
sys.exit() | ||
|
||
if testing: | ||
return args | ||
|
||
# Run the specified module(s) | ||
args.func(args) | ||
|
||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ name = "isoslam" | |
description = "Tools for processing and summarising SLAMSeq experiments." | ||
readme = "README.md" | ||
license = {text = "MIT License"} | ||
requires-python = ">=3.9" | ||
requires-python = ">=3.10" | ||
dynamic = ["version"] | ||
authors = [ | ||
{name = "Jack Riley", email = "[email protected]"}, | ||
|
@@ -19,7 +19,6 @@ authors = [ | |
] | ||
classifiers = [ | ||
"Programming Language :: Python :: 3", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: 3.10", | ||
"Programming Language :: Python :: 3.11", | ||
"Programming Language :: Python :: 3.12", | ||
|
@@ -268,7 +267,7 @@ files = [ | |
"isoslam", | ||
"tests" | ||
] | ||
python_version = "3.9" | ||
python_version = "3.10" | ||
strict = true | ||
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] | ||
warn_unreachable = true | ||
|
@@ -278,4 +277,7 @@ exclude = [ | |
|
||
[[tool.mypy.overrides]] | ||
module = [ "numpy.*", ] | ||
ignore_missing_imports = true | ||
ignore_missing_imports = true | ||
|
||
[project.scripts] | ||
isoslam = "isoslam.processing:entry_point" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
"""Tests of the processing modules entry point, argument parsing and ability to correctly select programs.""" | ||
|
||
from collections.abc import Callable | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from isoslam import processing | ||
|
||
|
||
@pytest.mark.parametrize( | ||
("option", "help_message"), | ||
[ | ||
pytest.param(["-h"], "usage:", id="Single letter help"), | ||
pytest.param(["--help"], "program", id="Multiple letter help"), | ||
pytest.param( | ||
["process"], | ||
"Process all files and run all summary plotting and statistics.", | ||
id="process module", | ||
marks=pytest.mark.xfail(reason="work in progress"), | ||
), | ||
], | ||
) | ||
def test_entry_point_help(option: str, help_message: str, capsys: pytest.CaptureFixture) -> None: | ||
"""Test the entry_point()'s help argument.""" | ||
try: | ||
processing.entry_point(manually_provided_args=option) | ||
except SystemExit: | ||
pass | ||
output = capsys.readouterr().out | ||
assert help_message in output | ||
|
||
|
||
@pytest.mark.parametrize( | ||
("options", "expected_function", "expected_args"), | ||
[ | ||
pytest.param( | ||
["--config", "dummy/config/dir/config.yaml", "process"], | ||
processing.process, | ||
{"config_file": Path("dummy/config/dir/config.yaml")}, | ||
id="dummy config and process", | ||
), | ||
pytest.param( | ||
["--config", "dummy/config/dir/config.yaml", "process", "--bam-file", "data/bam/some.bam"], | ||
processing.process, | ||
{"config_file": Path("dummy/config/dir/config.yaml"), "bam_file": Path("data/bam/some.bam")}, | ||
id="dummy config, bam file and process", | ||
), | ||
pytest.param( | ||
[ | ||
"--config", | ||
"dummy/config/dir/config.yaml", | ||
"--output-dir", | ||
"output", | ||
"process", | ||
"--bam-file", | ||
"data/bam/some.bam", | ||
], | ||
processing.process, | ||
{ | ||
"config_file": Path("dummy/config/dir/config.yaml"), | ||
"output_dir": Path("output"), | ||
"bam_file": Path("data/bam/some.bam"), | ||
}, | ||
id="dummy config and output, process with bam file", | ||
), | ||
pytest.param( | ||
[ | ||
"--config", | ||
"dummy/config/dir/config.yaml", | ||
"--output-dir", | ||
"output", | ||
"process", | ||
"--bam-file", | ||
"data/bam/some.bam", | ||
"--gtf-file", | ||
"data/gtf/some.gtf", | ||
"--bed-file", | ||
"data/bed/some.bed", | ||
"--vcf-file", | ||
"data/vcf/some.vcf.gz", | ||
], | ||
processing.process, | ||
{ | ||
"config_file": Path("dummy/config/dir/config.yaml"), | ||
"output_dir": Path("output"), | ||
"bam_file": Path("data/bam/some.bam"), | ||
"gtf_file": Path("data/gtf/some.gtf"), | ||
"bed_file": Path("data/bed/some.bed"), | ||
"vcf_file": Path("data/vcf/some.vcf.gz"), | ||
}, | ||
id="dummy config and output, process with all files", | ||
), | ||
], | ||
) | ||
def test_entry_point_sub_parsers(options: str, expected_function: Callable, expected_args: dict) -> None: | ||
"""Test the correct function is returned by each subparser.""" | ||
returned_args = processing.entry_point(manually_provided_args=options, testing=True) | ||
assert returned_args.func == expected_function | ||
returned_args_dict = vars(returned_args) | ||
for argument, value in expected_args.items(): | ||
assert returned_args_dict[argument] == value |