Skip to content

Solubility usability prediction NetSolP - #78

Merged
fmoorhof merged 6 commits into
mainfrom
solubility-usability-prediction-NetSolP
Jun 25, 2026
Merged

fmoorhof merged 6 commits into
mainfrom
solubility-usability-prediction-NetSolP

Conversation

@fmoorhof

@fmoorhof fmoorhof commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

Introduce configurable prediction pipeline that augments SelectZyme runs with optional EC number and solubility/usability predictions based on ESM1b embeddings.

New Features:

  • Add NetSolP-based solubility and usability prediction integration driven by project configuration.
  • Add CLEAN-based EC prediction module that runs on precomputed ESM1b embeddings and writes merged results to the analysis dataset.

Enhancements:

  • Refactor prediction logic into a reusable backend routine and separate EC prediction helper, simplifying the main application flow.
  • Extend configuration to toggle prediction features and update README with setup instructions for CLEAN and NetSolP.

Documentation:

  • Document setup and usage of optional EC and solubility predictors, including required external repositories and model weights.

fmoorhof added 5 commits June 23, 2026 18:16
style: remove terminal printouts
op: remove dependencies from project and install NetSolP seperately, as onnx models can not be used from esm1b base. seperated prediction required
WIP: GPU detection for performance optimization needed
error message: pandas.errors.MergeError: Passing 'suffixes' which cause duplicate columns {'CLEAN_probability_x', 'CLEAN_EC_pred_x'} is not allowed.
style: outsource code from app.py
…nal packages works?

Note: Deployment yet untested on absence of additional predictors. Tried to import only when called but not sure if this was enough.
@sourcery-ai

sourcery-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors prediction logic into a reusable backend function and adds optional NetSolP-based solubility/usability prediction alongside existing CLEAN EC-number prediction, with corresponding config flags and README setup instructions.

Sequence diagram for prediction flow using CLEAN and NetSolP

sequenceDiagram
    participant App as app_main
    participant Backend as run_predictions
    participant CLEAN as run_clean_inference_with_embeddings
    participant NetSolP as get_preds

    App->>Backend: run_predictions(df, X, config, analysis_path)
    alt EC_prediction_enabled_and_missing
        Backend->>CLEAN: run_clean_inference_with_embeddings(sequence_label_esm_emb_dict, emb_train_path, ec_csv_path, model_ckpt_path, out_csv, gmm, device)
        CLEAN-->>Backend: df_clean
        Backend->>Backend: df.merge(df_clean[accession, CLEAN_EC_pred, CLEAN_probability])
    end
    alt Solubility_prediction_enabled_and_missing
        Backend->>NetSolP: get_preds(df, args)
        NetSolP-->>Backend: df_with_netSolP
    end
    Backend-->>App: df
Loading

File-Level Changes

Change Details Files
Refactor EC prediction logic out of the main app flow into a reusable backend prediction entry point that also orchestrates optional NetSolP solubility/usability predictions based on config and existing columns.
  • Replace inlined CLEAN EC prediction in app.py with a call to a new run_predictions function in backend.predict
  • Implement run_predictions to conditionally run CLEAN EC prediction only when EC-related columns are missing and config enables it
  • Implement conditional NetSolP solubility/usability prediction in run_predictions using a locally constructed argparse.Namespace and update the dataframe in place
selectzyme/backend/predict.py
app.py
Extract CLEAN EC inference utilities into a dedicated backend module with minimal interface surface and testing harness.
  • Move CLEAN helper functions and run_clean_inference_with_embeddings workflow from backend.predict into a new backend.predict_ec module
  • Preserves original CLI-style main block for local testing of CLEAN predictions with example data and paths
selectzyme/backend/predict_ec.py
Introduce NetSolP-based solubility/usability prediction helper and hook it into the backend predictions flow.
  • Create backend.predict_solubility.get_preds to wrap NetSolP PredictionServer APIs and add netSolP_solubility and netSolP_usability columns to the dataframe
  • Implement NetSolP batching using FastaBatchedDataset and BatchConverter with ensemble averaging across five model splits
  • Provide a simple main block to run NetSolP predictions on example fasta input
selectzyme/backend/predict_solubility.py
Document and configure the new optional predictor features and adjust CLEAN installation instructions.
  • Extend README with an "Additional predictors" section describing CLEAN and NetSolP installation/weights locations and note that deployment without these is untested
  • Update CLEAN clone URL to fork under fmoorhof and clarify hard-coded paths
  • Add project.predictions.solubility and project.predictions.ec flags to the sample test_config.yml to control predictor execution
README.md
results/input_configs/test_config.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 5 issues, and left some high level feedback:

  • In run_predictions, df_clean is only defined inside the CLEAN branch but is merged unconditionally afterwards; if EC prediction is disabled or plm_model is not esm1b, this will raise a NameError—guard the merge or initialise df_clean appropriately.
  • Using argparse.ArgumentParser().parse_args() inside run_predictions to build NetSolP args will consume/validate the process-wide CLI arguments and can conflict with the main app; consider constructing a simple argparse.Namespace or a plain object/dict instead of parsing global CLI args here.
  • In predict_solubility.get_preds, alphabet_path is hard-coded to NetSolP-1.0/PredictionServer/models/ and ignores args.MODELS_PATH; this makes the setup brittle and inconsistent with the README, so it would be better to derive the path from args.MODELS_PATH.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `run_predictions`, `df_clean` is only defined inside the CLEAN branch but is merged unconditionally afterwards; if EC prediction is disabled or `plm_model` is not `esm1b`, this will raise a `NameError`—guard the merge or initialise `df_clean` appropriately.
- Using `argparse.ArgumentParser().parse_args()` inside `run_predictions` to build NetSolP `args` will consume/validate the process-wide CLI arguments and can conflict with the main app; consider constructing a simple `argparse.Namespace` or a plain object/dict instead of parsing global CLI args here.
- In `predict_solubility.get_preds`, `alphabet_path` is hard-coded to `NetSolP-1.0/PredictionServer/models/` and ignores `args.MODELS_PATH`; this makes the setup brittle and inconsistent with the README, so it would be better to derive the path from `args.MODELS_PATH`.

## Individual Comments

### Comment 1
<location path="selectzyme/backend/predict.py" line_range="11" />
<code_context>
+def run_predictions(df, X, config, analysis_path):
+
+    # predict EC numbers with CLEAN if they dont exist yet
+    if df.CLEAN_EC_pred.isnull().all() and df.CLEAN_probability.isnull().all():
+        if config["project"]["plm"]["plm_model"] == "esm1b" and config["project"]["predictions"]["ec"] == True:
+            from selectzyme.backend.predict_ec import run_clean_inference_with_embeddings
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against `df_clean` being undefined when EC prediction is disabled or a different PLM model is used.

`df_clean` is defined only inside `if config["project"]["plm"]["plm_model"] == "esm1b" and config["project"]["predictions"]["ec"] == True:`. When that condition is false, the outer `if` still proceeds to the `merge`, but `df_clean` will be undefined and cause a runtime error.

Consider either moving the `merge` inside the inner `if`, or initializing `df_clean = None` before it and only merging when `df_clean` is not `None`, so the control flow matches when EC predictions are actually produced.
</issue_to_address>

### Comment 2
<location path="selectzyme/backend/predict.py" line_range="35-44" />
<code_context>
+        logging.info("Running NetSolP predictions. This might take a long time.")
+
+        # hard coded configurations to pass to NetSolP package
+        parser = argparse.ArgumentParser()
+        parser.add_argument("--MODEL_TYPE", default="ESM1b")
+        parser.add_argument("--MODELS_PATH", 
+                            default="/scratch/global_1/fmoorhof/NetSolP/models/")  # NetSolP-1.0/PredictionServer/models
+        parser.add_argument("--NUM_THREADS", default=os.cpu_count(), type=int)
+        parser.add_argument(
+            "--PREDICTION_TYPE",
+            default="SU",
+            choices=['S', 'U', 'SU'],
+            type=str,
+            help="Either Solubility(S), Usability(U) or Both"
+        )
+        args = parser.parse_args()
+
+        df = get_preds(df=df, args=args)
</code_context>
<issue_to_address>
**suggestion:** Avoid calling `argparse.ArgumentParser().parse_args()` inside a library/helper function.

Calling `parse_args()` here consumes global CLI flags and can cause unexpected exits or conflicts when this helper is used from other entry points (e.g., other CLIs, web apps, notebooks).

Consider instead:
- Constructing a simple config object in code (e.g., `types.SimpleNamespace` or a dataclass), or
- Accepting an `args`-like parameter in `run_predictions`

so that this function remains free of global CLI side effects.

Suggested implementation:

```python
    # predict solubility and usability with NetSolP if they dont exist yet
    if (
        config["project"]["predictions"]["solubility"] is True
        and df.netSolP_solubility.isnull().all()
        and df.netSolP_usability.isnull().all()
    ):
        from types import SimpleNamespace
        from selectzyme.backend.predict_solubility import get_preds

        logging.info("Running NetSolP predictions. This might take a long time.")

        # hard coded configurations to pass to NetSolP package
        args = SimpleNamespace(
            MODEL_TYPE="ESM1b",
            MODELS_PATH="/scratch/global_1/fmoorhof/NetSolP/models/",  # NetSolP-1.0/PredictionServer/models
            NUM_THREADS=os.cpu_count(),
            PREDICTION_TYPE="SU",  # Either Solubility(S), Usability(U) or Both
        )

        df = get_preds(df=df, args=args)

    return df

```

- Ensure `os` is imported at the top of `selectzyme/backend/predict.py` if it is not already: `import os`.
- If you prefer to avoid importing `SimpleNamespace` inside the function, move `from types import SimpleNamespace` to the top-level imports instead.
- If other callers already construct and pass an `args` object into `get_preds`, you may later want to refactor `get_preds` to accept a more explicit config type (e.g., a dataclass) instead of relying on attribute-based namespaces.
</issue_to_address>

### Comment 3
<location path="selectzyme/backend/predict_solubility.py" line_range="14" />
<code_context>
+
+
+def get_preds(df, args):
+    alphabet_path = os.path.join("NetSolP-1.0/PredictionServer/models/", "ESM1b_alphabet.pkl")  # args.MODELS_PATH
+
+    with open(alphabet_path, "rb") as f:
</code_context>
<issue_to_address>
**issue (bug_risk):** Use the configured `MODELS_PATH` instead of a hard-coded NetSolP model directory.

`alphabet_path` is hard-coded and doesn’t use `args.MODELS_PATH`, even though that’s already configured in `__main__`. This couples the code to a specific directory layout and CWD.

Instead, derive the path from the configured models directory, e.g.:
```python
alphabet_path = os.path.join(args.MODELS_PATH, "ESM1b_alphabet.pkl")
```
so the model location is controlled via configuration rather than a fixed relative path.
</issue_to_address>

### Comment 4
<location path="README.md" line_range="40-42" />
<code_context>

-## EC number prediction with CLEAN
+## Additional predictors based on ESM1b
+Note: Deployment yet untested on absence of additional predictors. Tried to import only when called but not sure if this was enough.
+### EC number prediction with CLEAN
+Install CLEAN, download weights and place them into the hard coded locations.
</code_context>
<issue_to_address>
**suggestion (typo):** Clarify and slightly rephrase the note about deployment being untested for better grammar.

Consider rephrasing this note for clarity and grammar, for example:

"Note: Deployment is yet untested in the absence of additional predictors. Imports are deferred until the predictors are called, but it is not yet verified that this is sufficient."

```suggestion
## Additional predictors based on ESM1b
Note: Deployment is yet untested in the absence of additional predictors. Imports are deferred until the predictors are called, but it is not yet verified that this is sufficient.
### EC number prediction with CLEAN
```
</issue_to_address>

### Comment 5
<location path="README.md" line_range="43-48" />
<code_context>
+## Additional predictors based on ESM1b
+Note: Deployment yet untested on absence of additional predictors. Tried to import only when called but not sure if this was enough.
+### EC number prediction with CLEAN
+Install CLEAN, download weights and place them into the hard coded locations.
 ```
-git clone https://github.com/tttianhao/CLEAN.git
</code_context>
<issue_to_address>
**nitpick (typo):** Use standard hyphenation for "hard-coded" in both installation instructions.

Please change both occurrences (in the CLEAN and NetSolP sections) from "hard coded" to "hard-coded locations" to match standard technical writing conventions.

Suggested implementation:

```
Install CLEAN, download weights and place them into the hard-coded locations.

```

```
Install NetSolP, download weights and place them into the hard-coded locations.

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread selectzyme/backend/predict.py
Comment thread selectzyme/backend/predict.py Outdated
Comment thread selectzyme/backend/predict_solubility.py Outdated
Comment thread README.md
Comment on lines +40 to +42
## Additional predictors based on ESM1b
Note: Deployment yet untested on absence of additional predictors. Tried to import only when called but not sure if this was enough.
### EC number prediction with CLEAN

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Clarify and slightly rephrase the note about deployment being untested for better grammar.

Consider rephrasing this note for clarity and grammar, for example:

"Note: Deployment is yet untested in the absence of additional predictors. Imports are deferred until the predictors are called, but it is not yet verified that this is sufficient."

Suggested change
## Additional predictors based on ESM1b
Note: Deployment yet untested on absence of additional predictors. Tried to import only when called but not sure if this was enough.
### EC number prediction with CLEAN
## Additional predictors based on ESM1b
Note: Deployment is yet untested in the absence of additional predictors. Imports are deferred until the predictors are called, but it is not yet verified that this is sufficient.
### EC number prediction with CLEAN

Comment thread README.md
Comment on lines +43 to 48
Install CLEAN, download weights and place them into the hard coded locations.
```
git clone https://github.com/tttianhao/CLEAN.git
git clone https://github.com/fmoorhof/CLEAN.git
cd CLEAN/app
# get model weights (see below)
python build.py install # requires activated venv/conda

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (typo): Use standard hyphenation for "hard-coded" in both installation instructions.

Please change both occurrences (in the CLEAN and NetSolP sections) from "hard coded" to "hard-coded locations" to match standard technical writing conventions.

Suggested implementation:

Install CLEAN, download weights and place them into the hard-coded locations.

Install NetSolP, download weights and place them into the hard-coded locations.

…ded NetSolP model directory.

[sourcery suggestions]
@fmoorhof
fmoorhof merged commit 82485b1 into main Jun 25, 2026
3 checks passed
@fmoorhof
fmoorhof deleted the solubility-usability-prediction-NetSolP branch June 25, 2026 05:06
@fmoorhof fmoorhof changed the title Solubility usability prediction net sol p Solubility usability prediction NetSolP Jun 25, 2026
@fmoorhof fmoorhof added this to the core milestone Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant