From 66ba8b5274ed9f7a1c9ecb9a16a212d22c886b5a Mon Sep 17 00:00:00 2001 From: Rita Silva Date: Thu, 12 Mar 2026 10:20:07 +0000 Subject: [PATCH 1/4] move python scripts to main folder --- .Rbuildignore | 3 ++- README.Rmd | 4 ++-- README.md | 4 ++-- {inst/python => python}/README.md | 0 {inst/python => python}/markeR_to_python.py | 0 {inst/python => python}/run_marker_function.py | 0 6 files changed, 6 insertions(+), 5 deletions(-) rename {inst/python => python}/README.md (100%) rename {inst/python => python}/markeR_to_python.py (100%) rename {inst/python => python}/run_marker_function.py (100%) diff --git a/.Rbuildignore b/.Rbuildignore index 5d97a0bf..7f79104d 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -20,4 +20,5 @@ ^\\.git$ ^codecov\.yml$ ^vignettes/articles$ -^data_aux$ \ No newline at end of file +^data_aux$ +^python$ \ No newline at end of file diff --git a/README.Rmd b/README.Rmd index 13d6d7a5..5aa6a737 100644 --- a/README.Rmd +++ b/README.Rmd @@ -241,10 +241,10 @@ Filters can be applied based on similarity thresholds (e.g., minimum Jaccard, OR ## Python Bridge For users who prefer Python, a lightweight bridge is available in -`inst/python/` that allows calling any `markeR` function from a Python +`python/` that allows calling any `markeR` function from a Python environment via [`rpy2`](https://rpy2.github.io/). It includes a tutorial workflow script and a generic command-line wrapper. See -[`inst/python/README.md`](inst/python/README.md) for installation +[`python/README.md`](inst/python/README.md) for installation instructions and usage examples. diff --git a/README.md b/README.md index f2e267d6..7b1e3454 100644 --- a/README.md +++ b/README.md @@ -288,10 +288,10 @@ Jaccard, OR, or Fisher’s test p-value). ## Python Bridge For users who prefer Python, a lightweight bridge is available in -`inst/python/` that allows calling any `markeR` function from a Python +`python/` that allows calling any `markeR` function from a Python environment via [`rpy2`](https://rpy2.github.io/). It includes a tutorial workflow script and a generic command-line wrapper. See -[`inst/python/README.md`](inst/python/README.md) for installation +[`python/README.md`](inst/python/README.md) for installation instructions and usage examples. ## Contact diff --git a/inst/python/README.md b/python/README.md similarity index 100% rename from inst/python/README.md rename to python/README.md diff --git a/inst/python/markeR_to_python.py b/python/markeR_to_python.py similarity index 100% rename from inst/python/markeR_to_python.py rename to python/markeR_to_python.py diff --git a/inst/python/run_marker_function.py b/python/run_marker_function.py similarity index 100% rename from inst/python/run_marker_function.py rename to python/run_marker_function.py From d4cc8f5a6aba0d29af7672203039ae5141cfd00c Mon Sep 17 00:00:00 2001 From: Rita Silva Date: Thu, 12 Mar 2026 10:48:56 +0000 Subject: [PATCH 2/4] clean up python scripts --- .gitignore | 1 + python/README.md | 22 ++++++++++++++-------- python/markeR_to_python.py | 20 ++++---------------- python/requirements.txt | 9 +++++++++ python/run_marker_function.py | 19 ++++++++++++------- 5 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 python/requirements.txt diff --git a/.gitignore b/.gitignore index ea55e2da..32e172ac 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ markeR.Rproj inst/doc data_aux markeR.Rcheck +/python/.venv diff --git a/python/README.md b/python/README.md index c1f66512..a2f7b7b6 100644 --- a/python/README.md +++ b/python/README.md @@ -12,14 +12,20 @@ Bioconductor R package **markeR** via `rpy2`. ## Prerequisites -* R (>=.4.5) installed and on your `PATH`. -* A Python virtual environment. Install dependencies with: - -```bash -python -m venv .venv -source .venv/bin/activate -pip install -r requirements.txt -``` +* R (>=4.5) installed and on your `PATH`. +* A Python virtual environment. A `requirements.txt` file is provided in + this folder listing the needed packages (`rpy2`, `pandas`, `numpy` plus + optional `ipython`/`jupyter` for notebook usage). + To set up the environment: + + ```bash + python -m venv .venv + source .venv/bin/activate + pip install -r requirements.txt + ``` + + After activation you can run the helper scripts using `python` from the + same environment. ## Quick start diff --git a/python/markeR_to_python.py b/python/markeR_to_python.py index 83256c10..a2e3b09f 100644 --- a/python/markeR_to_python.py +++ b/python/markeR_to_python.py @@ -60,12 +60,6 @@ # converting. helpers below wrap the recommended API. -def _to_r(obj): - """Convert a pandas object to an R object using the current converter.""" - with conversion.localconverter(ro.default_converter + pandas2ri.converter): - return conversion.py2rpy(obj) - - def _to_py(obj): """Convert an R object to a pandas/numpy equivalent.""" with conversion.localconverter(ro.default_converter + pandas2ri.converter): @@ -175,7 +169,6 @@ def plot_r_function(func_name: str, *args, width=800, height=600, filename=None, def ensure_bioc_installed() -> None: """Install Bioconductor's package manager if it is not already present.""" - utils = importr("utils") biocinstaller = "BiocManager" if not isinstalled(biocinstaller): ro.r('install.packages("{0}")'.format(biocinstaller)) @@ -189,14 +182,9 @@ def install_markeR() -> None: the package should be loadable via `importr("markeR")`. """ ensure_bioc_installed() - # use importr to check presence rather than only the isinstalled helper - try: - importr("markeR") - except Exception: - # attempt installation if import failed + if not isinstalled("markeR"): ro.r('BiocManager::install("markeR", ask=FALSE, update=FALSE)') - # load into namespace for side effects - ro.r('library(markeR)') + ro.r('library(markeR)') def get_markeR_functions() -> ro.Environment: @@ -204,7 +192,7 @@ def get_markeR_functions() -> ro.Environment: Example: mark = get_markeR_functions() - imputed = mark.rgImpute(...) + scores = mark.CalculateScores(data=counts, metadata=metadata, gene_sets=genesets, method="logmedian") """ install_markeR() # importing via importr is more reliable than accessing `ro.r['markeR']`. @@ -330,4 +318,4 @@ def tutorial_benchmark(output_file=None): print(" example: python markeR_to_python.py --tutorial --output my_plot.png") else: print("usage: python markeR_to_python.py --tutorial [--output FILENAME]") - print("See the module docstring for more details.") + print("See the module docstring for more details.") \ No newline at end of file diff --git a/python/requirements.txt b/python/requirements.txt new file mode 100644 index 00000000..fdb0e44a --- /dev/null +++ b/python/requirements.txt @@ -0,0 +1,9 @@ +# install packages for markeR_to_python script: +# pip install -r requirements.txt + +rpy2>=3.6 +pandas +numpy +# optional (for notebook inline display) +ipython +jupyter diff --git a/python/run_marker_function.py b/python/run_marker_function.py index 268fd552..5ca33375 100644 --- a/python/run_marker_function.py +++ b/python/run_marker_function.py @@ -25,6 +25,7 @@ import argparse import json import os +import re # Check dependencies _missing = [] @@ -42,7 +43,6 @@ def ensure_bioc_installed() -> None: """Install Bioconductor's package manager if it is not already present.""" - utils = importr("utils") biocinstaller = "BiocManager" if not isinstalled(biocinstaller): ro.r('install.packages("{0}")'.format(biocinstaller)) @@ -52,11 +52,9 @@ def ensure_bioc_installed() -> None: def install_markeR() -> None: """Install the markeR package from Bioconductor if not already installed.""" ensure_bioc_installed() - try: - importr("markeR") - except Exception: + if not isinstalled("markeR"): ro.r('BiocManager::install("markeR", ask=FALSE, update=FALSE)') - ro.r('library(markeR)') + ro.r('library(markeR)') def load_example_data(): @@ -113,7 +111,8 @@ def parse_parameter(value: str): except (json.JSONDecodeError, ValueError): pass - # Default: treat as string + # Default: treat as string, escaping any internal quotes + value = value.replace('"', '\\"') return f'"{value}"' @@ -272,6 +271,12 @@ def main(): return func_name = sys.argv[1] + + # Validate function name to prevent code injection + if not re.match(r'^[A-Za-z][A-Za-z0-9_.]*$', func_name): + sys.exit(f"Error: invalid function name '{func_name}'. " + "Function names must start with a letter and contain only letters, digits, dots or underscores.") + output_file = None width = 800 height = 600 @@ -358,4 +363,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file From 11c0fce0af1bb8ad82d38051c5b96e0361099612 Mon Sep 17 00:00:00 2001 From: Rita Silva Date: Thu, 12 Mar 2026 11:15:45 +0000 Subject: [PATCH 3/4] clean up and fix build after python scripts added --- .Rbuildignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 7f79104d..d713df39 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -20,5 +20,5 @@ ^\\.git$ ^codecov\.yml$ ^vignettes/articles$ -^data_aux$ -^python$ \ No newline at end of file +^data_aux$ +^python(/.*)?$ \ No newline at end of file From 3356098abea266fbe221ca9ae6c491580a29f030 Mon Sep 17 00:00:00 2001 From: Rita Silva Date: Thu, 12 Mar 2026 12:02:29 +0000 Subject: [PATCH 4/4] bump version to 1.1.2 --- DESCRIPTION | 2 +- NEWS.md | 10 ++++++++++ README.Rmd | 2 +- README.md | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index f26c26a2..17cce5fd 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: markeR Title: An R Toolkit for Evaluating Gene Signatures as Phenotypic Markers -Version: 1.1.1 +Version: 1.1.2 Authors@R: c( person("Rita", "Martins-Silva", diff --git a/NEWS.md b/NEWS.md index 16ad0ff4..4d66e94e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,13 @@ +# markeR 1.1.2 (12 Mar, 2026) + +## Minor Changes +- Moved Python bridge scripts from `inst/python/` to a top-level `python/` + directory, as these are supplementary scripts not part of the R package itself. +- Added `requirements.txt` to the `python/` directory listing all needed + Python dependencies (`rpy2`, `pandas`, `numpy`, and optionally + `ipython` and `jupyter`) for easier environment setup. +- Removed redundant code snippets from the Python bridge scripts. + # markeR 1.1.1 (11 Mar, 2026) - Added `p.adjust.method` parameter across all functions performing or diff --git a/README.Rmd b/README.Rmd index 5aa6a737..94f25d9c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -30,7 +30,7 @@ knitr::opts_chunk$set( > **To cite `markeR` please use:** > -> Martins-Silva R, Kaizeler A, Barbosa-Morais NL (2025). _markeR: An R Toolkit for Evaluating Gene Signatures as Phenotypic Markers_. doi:10.18129/B9.bioc.markeR, R package version 1.1.1, https://bioconductor.org/packages/markeR. +> Martins-Silva R, Kaizeler A, Barbosa-Morais NL (2025). _markeR: An R Toolkit for Evaluating Gene Signatures as Phenotypic Markers_. doi:10.18129/B9.bioc.markeR, R package version 1.1.2, https://bioconductor.org/packages/markeR. The folder `inst/Paper/` is in the **paper** branch and contains all scripts and materials used in the original `markeR` paper to reproduce analyses and figures. You can browse it [here](https://github.com/DiseaseTranscriptomicsLab/markeR/tree/paper/inst/Paper). diff --git a/README.md b/README.md index 7b1e3454..0daabf81 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ across experimental and clinical phenotypes. > > Martins-Silva R, Kaizeler A, Barbosa-Morais NL (2025). *markeR: An R > Toolkit for Evaluating Gene Signatures as Phenotypic Markers*. -> , R package version 1.1.1, +> , R package version 1.1.2, > . The folder `inst/Paper/` is in the **paper** branch and contains all