Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,38 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
r2g2.egg-info/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# R
.RData
.Rhistory

# Mac
.DS_Store

# IDEs
.vscode/
.idea/

# Project specific
out_1/
test_1/
22 changes: 18 additions & 4 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
Copyright 22 Jul 2020 BLANKENBERGLAB
MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Copyright (c) 2020 BLANKENBERGLAB

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
5 changes: 4 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
include r2g2/parsers/FakeArg.r
include README.md
include LICENSE
include requirements.txt
include r2g2/parsers/FakeArg.r
46 changes: 29 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
### Installation Instructions and Requirements

```
conda create -n r2g2 conda-forge::rpy2=3.6.2
conda create -n r2g2 -c conda-forge rpy2=3.6.2 r-base=4.4.3 python=3.12.11 r-r6=2.6.1 r-argparse=2.2.5 r-r6=2.6.1 r-argparse=2.2.5
conda activate r2g2
conda install r-r6=2.6.1 r-argparse=2.2.5
pip install requests packaging


python=3.13
R=4.4.3
pip install r2g2==0.1.1

```


# R2-G2 Automatically Generates Galaxy tools on a per-function basis from any R Library

```
$ ./bin/r2g2_on_package.py --help
usage: r2g2_on_package.py [-h] --name NAME [--package_name PACKAGE_NAME]
[--package_version PACKAGE_VERSION] [--out OUT]
[--create_load_matrix_tool]
[--galaxy_tool_version GALAXY_TOOL_VERSION]
usage: r2g2-package [-h] --name NAME [--package_name PACKAGE_NAME] [--package_version PACKAGE_VERSION] [--out OUT] [--create_load_matrix_tool]
[--galaxy_tool_version GALAXY_TOOL_VERSION]

optional arguments:
options:
-h, --help show this help message and exit
--name NAME Package Name
--package_name PACKAGE_NAME
Expand All @@ -31,21 +23,41 @@ optional arguments:
[Conda] Package Version
--out OUT Output directory
--create_load_matrix_tool
Output a tool that will create an RDS from a tabular
matrix
Output a tool that will create an RDS from a tabular matrix
--galaxy_tool_version GALAXY_TOOL_VERSION
Additional Galaxy Tool Version
```

# R2-G2 Automatically Generates Galaxy tools on R-Script based on argument parsing

```
usage: r_script/r2g2_on_r_script.py [-h] -r R_FILE_NAME [-o OUTPUT_DIR]
usage: r2g2-script [-h] [-r R_SCRIPT_NAME] [-f R_SCRIPTS] [-o OUTPUT_DIR] [-p PROFILE] [-d DESCRIPTION] [-s DEPENDENCIES] [-v TOOL_VERSION] [-c CITATION_DOI]
[-u USER_DEFINE_OUTPUT_PARAM] [-i USER_DEFINE_INPUT_PARAM]

optional arguments:
options:
-h, --help show this help message and exit
-r R_SCRIPT_NAME, --r_script_name R_SCRIPT_NAME
Provide the path of an R script...
-f R_SCRIPTS, --r_scripts R_SCRIPTS
A path of a text file containing full path of R scripts.
-o OUTPUT_DIR, --output_dir OUTPUT_DIR
-p PROFILE, --profile PROFILE
-d DESCRIPTION, --description DESCRIPTION
tool based on R script
-s DEPENDENCIES, --dependencies DEPENDENCIES
Extract dependency information..
-v TOOL_VERSION, --tool_version TOOL_VERSION
Galaxy tool version..
-c CITATION_DOI, --citation_doi CITATION_DOI
Comma separated Citation DOI.
-u USER_DEFINE_OUTPUT_PARAM, --user_define_output_param USER_DEFINE_OUTPUT_PARAM
Rather guessing output params, user can define output params in specific format. Ex. 'name:protein,format:pdb,label:protein
file,from_work_directory;name:ligand,format:pdb,label:ligand file,from_work_directory'
-i USER_DEFINE_INPUT_PARAM, --user_define_input_param USER_DEFINE_INPUT_PARAM
List of input parameters to be treated as data inputs, comma separated. Ex. 'input_file,reference_data'
```


### Examples

For a complete example of using R2G2 with the DEP Analysis package, please see the [DEP Analysis Scripts README](tests/DEP_Analysis_Scripts/README.md).
1 change: 0 additions & 1 deletion r2g2/anvio.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@
It brings together many aspects of today’s cutting-edge genomic, metagenomic, and metatranscriptomic analysis practices to address a wide array of needs.
"""


class Parameter( object ):
_output_startswith = ('output', 'export')
_default_default = ''
Expand Down
95 changes: 77 additions & 18 deletions r2g2/parsers/r_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
from rpy2.robjects.packages import PackageNotInstalledError
import xml.etree.ElementTree as ET
from xml.dom import minidom
from xml.sax.saxutils import quoteattr
# from r_script_to_galaxy_wrapper import FakeArg
from r2g2.anvio import FakeArg, SKIP_PARAMETER_NAMES
from r2g2.anvio import FakeArg, SKIP_PARAMETER_NAMES, Parameter
from pathlib import Path
import re
import functools
Expand All @@ -20,8 +21,39 @@ def pretty_xml(element):
reparsed = minidom.parseString(rough_str)
return reparsed.toprettyxml(indent=" ")

class ParameterData(Parameter):
def get_type(self):
return 'data'

def to_xml_param(self):
data_format = self.info_dict.get('data_format', 'txt')
label = self.info_dict.get('label', self.get_label())
return """<param name=%s type="data" format="%s" label=%s optional="%s" argument=%s help=%s/>""" % (
quoteattr( self.get_input_cmd_name() ),
data_format,
quoteattr(label),
self.get_optional(),
self.get_argument(),
self.get_help(),
)

class CustomFakeArg(FakeArg):
def __init__(self, *args, **kwargs):
ignore_params = kwargs.pop('ignore_params', [])
if ignore_params is None:
ignore_params = []
self.ignore_params = [self.clean_arg_name(p) for p in ignore_params]

data_params = kwargs.pop('data_params', None)

self.data_params = {}
if data_params:
if isinstance(data_params, list):
for p in data_params:
self.data_params[self.clean_arg_name(p)] = {'format': 'txt'}
elif isinstance(data_params, dict):
for k, v in data_params.items():
self.data_params[self.clean_arg_name(k)] = v

self.param_cat = {}
# call parent constructor
Expand Down Expand Up @@ -111,9 +143,11 @@ def dict_to_xml_and_command(self, spec, parent=None, subparser_name=None,
# Normal params
for opt in spec.get("groups", {}).get("options", []):
if opt != "--help" and "output" not in opt:
parent.append(self.generate_param( opt))
# print(" " * level + f"{opt}{' '}'${full_name}.{self.clean_arg_name(opt)}'\n")
cmd_parts.append("\t\t\t\t\t\t\t" * level + f"{opt}{' '}'${full_name}.{self.clean_arg_name(opt)}'")
res = self.generate_param( opt)
if res is not None:
parent.append(res)
# print(" " * level + f"{opt}{' '}'${full_name}.{self.clean_arg_name(opt)}'\n")
cmd_parts.append("\t\t\t\t\t\t\t" * level + f"{opt}{' '}'${full_name}.{self.clean_arg_name(opt)}'")

# Nested subparsers
if spec.get("subparsers"):
Expand Down Expand Up @@ -180,7 +214,9 @@ def mutual_conditional(self, spec):
when2 = ET.SubElement(cond2, "when", value=o)
mut_cond_command = f"\n#if '$mut_{group_name}.{group_name}_selector' == '%s'\n%s\n#end if\n"%(self.clean_arg_name(o), f" '${group_name}.{self.clean_arg_name(o)}'")
mut_command.append(mut_cond_command)
when2.append(self.generate_param(o))
res = self.generate_param(o)
if res is not None:
when2.append(res)
mut_list.append("\n".join(pretty_xml(cond2).split("\n")[1:]))

return "\n".join(mut_list), "\n".join(mut_command)
Expand All @@ -191,9 +227,11 @@ def flat_param_groups(self, spec):
for group in spec['groups'].keys():
for item in spec['groups'][group]:
if item != "--help" and "output" not in item:
param, command = self.generate_param( item, flat=True)
param_list.append("\n".join(pretty_xml(param).split("\n")[1:]))
command_list.append("\t\t\t"+command)
res = self.generate_param( item, flat=True)
if res:
param, command = res
param_list.append("\n".join(pretty_xml(param).split("\n")[1:]))
command_list.append("\t\t\t"+command)
return "\n".join(param_list), "\n".join(command_list)

def groups_params(self):
Expand All @@ -219,7 +257,14 @@ def clean_arg_name(self, arg: str) -> str:
def generate_param(self, opt, flat=False):
for d in self.oynaxraoret_get_params( {} ):
if d.name not in SKIP_PARAMETER_NAMES and d.is_input:
if d.name in self.ignore_params:
continue
if self.clean_arg_name(opt) == d.name:
if d.name in self.data_params:
d.info_dict['data_format'] = self.data_params[d.name].get('format', 'txt')
if 'label' in self.data_params[d.name]:
d.info_dict['label'] = self.data_params[d.name]['label']
d = ParameterData(d.name, d.arg_short, d.arg_long, d.info_dict)
xml_str = d.to_xml_param()
if flat:
return ET.fromstring(xml_str), d.to_cmd_line()
Expand Down Expand Up @@ -516,37 +561,42 @@ def param_info_parsing(parent_locals):
"""%(args_string)
return arg_str_function

def json_to_python(json_file):
def json_to_python(json_file, data_params=None, ignore_params=None):

data = clean_json(json_file)
parser_name = 'parser'
args_string = '\n '.join(data)
arg_str_function = f"""

# Format data_params as a python list string or None
data_params_str = str(data_params) if data_params else "None"
ignore_params_str = str(ignore_params) if ignore_params else "None"

arg_str_function = """
#!/usr/bin/env python
# from r_script_to_galaxy_wrapper import FakeArg
from r2g2.parsers.r_parser import CustomFakeArg
import json
import argparse

# def param_info_parsing(parent_locals):
# parser_1 = argparse.ArgumentParser()\n
# parser_1 = argparse.ArgumentParser()\\n
# globals().update(parent_locals)
# return parser_1

def r_script_argument_parsing(parent_locals, CustomFakeArg=CustomFakeArg):
def r_script_argument_parsing(parent_locals, CustomFakeArg=CustomFakeArg, data_params=None, ignore_params=None):
__description__ = "test"

parser = CustomFakeArg(description=__description__)\n %s
parser = CustomFakeArg(description=__description__, data_params=data_params, ignore_params=ignore_params)\n %s
globals().update(parent_locals)

param_info = param_info_parsing(dict(locals()))
# parser.param_cat = extract_simple_parser_info(param_info)

return parser

blankenberg_parameters = r_script_argument_parsing(dict(locals()))
blankenberg_parameters = r_script_argument_parsing(dict(locals()), data_params=%s, ignore_params=%s)

"""%(args_string)
"""%(args_string, data_params_str, ignore_params_str)

return arg_str_function

Expand Down Expand Up @@ -735,6 +785,7 @@ def normalize_argument(arg):
outputs = string.split(";")
xml_outputs = []
output_command = []
output_args = []

for block in outputs:
block = block.strip()
Expand All @@ -745,7 +796,7 @@ def normalize_argument(arg):

out = {
"format":"text",
"lable":"ouput data file",
"label":"ouput data file",
"output_argument":"None",
}

Expand All @@ -760,7 +811,15 @@ def normalize_argument(arg):
out["name"] = normalize_argument(out["output_argument"])

if not "None" == out["output_argument"]:
output_command.append(f'{out["output_argument"]} "${out["name"]}"\n')
# Ensure the output_argument is formatted as a CLI flag (prepend -- if not present)
cli_flag = out["output_argument"]
if not cli_flag.startswith("--"):
full_cli_flag = f'--{cli_flag}'
else:
full_cli_flag = cli_flag

output_command.append(f'{full_cli_flag} "${out["name"]}"\n')
output_args.append(out["output_argument"])
else:
raise ValueError("Output dataset argument is not defined in the user-defined parameters.")

Expand All @@ -774,7 +833,7 @@ def normalize_argument(arg):
)

xml_outputs.append(xml_tag)
return xml_outputs, output_command
return xml_outputs, output_command, output_args

def logical(value):
val = value.lower()
Expand Down
Loading