Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
Expand Down
4 changes: 2 additions & 2 deletions .github/skills/update-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ description: "Update the documentation and changelog, and reconcile GitHub issue
8. Determine whether changelog entries are managed by CI (for example, `python-semantic-release`).
- Check release automation config first (for example, `[tool.semantic_release]` in `pyproject.toml` and release workflow files) to identify the authoritative changelog file path and casing.
- If semantic-release (or equivalent) is configured to write changelog entries, **do not manually append a release section**. Instead, verify that the generated/release-bound changelog content is consistent with steps 2-7 and only make non-conflicting adjustments explicitly requested by the user.
- If no automation manages changelog entries, add the changelog to `mkdocs/docs/Changelog.md` (note the path/casing). Follow the existing format. If the file is empty or does not exist, use the Keep a Changelog format (https://keepachangelog.com) with sections: Added, Changed, Deprecated, Removed, Fixed, Security. Include the version number and release date at the top of the new section, and keep the issue/PR links added in step 5.
- If no automation manages changelog entries, add the changelog to `docs/Changelog.md` (note the path/casing). Follow the existing format. If the file is empty or does not exist, use the Keep a Changelog format (https://keepachangelog.com) with sections: Added, Changed, Deprecated, Removed, Fixed, Security. Include the version number and release date at the top of the new section, and keep the issue/PR links added in step 5.
9. Reconcile GitHub issues and milestones per the user's approval in step 7 (skip this step entirely if the GitHub CLI was unavailable in step 4).
- Assign approved issues and merged PRs that lack a milestone to the release milestone: `gh issue edit <N> --milestone "<title>"` / `gh pr edit <N> --milestone "<title>"`.
- Close each approved open issue with a comment linking the release: `gh issue close <N> --comment "Resolved in <version> release."`. Note that issues referenced with a closing keyword in a PR merged to the default branch are closed automatically by GitHub — do not double-close; only close issues that are still open after the merge.
- If the user approved creating a milestone, create it (`gh api repos/:owner/:repo/milestones -f title="<title>" -f state="open"`) and assign the release's issues/PRs to it before closing.
- Once every issue in the release milestone is closed, close the milestone: find its number via `gh api repos/:owner/:repo/milestones --jq '.[] | select(.title=="<title>") | .number'` then `gh api repos/:owner/:repo/milestones/<number> -X PATCH -f state="closed"`.
- Report the outcome of each action (issues closed, milestone closed/created, anything skipped) back to the user.
10. Now, review the documentation throughout the `mkdocs/docs` folder to ensure any version-specific information is updated for the new version. This includes updating version numbers, dates, and any other relevant details. In case new features are implemented, make sure to add documentation for those features as well into the appropriate sections. In case no sections exists, please create a new section for the new feature and add the documentation there. Make sure to format it properly and include any relevant examples or usage instructions.
10. Now, review the documentation throughout the `docs` folder to ensure any version-specific information is updated for the new version. This includes updating version numbers, dates, and any other relevant details. In case new features are implemented, make sure to add documentation for those features as well into the appropriate sections. In case no sections exists, please create a new section for the new feature and add the documentation there. Make sure to format it properly and include any relevant examples or usage instructions.
11. After updating the documentation, commit the changes to the repository with a clear commit message indicating that the documentation (and changelog verification/update mode) has been completed for the new release. If changelog sections are CI-generated, avoid committing manual duplicate release-note blocks unless explicitly requested. For example, "Update documentation and changelog workflow alignment for version X.Y.Z release." Reference the reconciled issues in the commit body where appropriate (e.g., `Refs #42, #43`). Commit on the current branch. Do not push or create a pull request unless explicitly instructed. If the repository requires pull requests for the main branch, note this to the user and stop.
131 changes: 117 additions & 14 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
run: |
uv run poe coverage

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: coverage-py${{ matrix.python-version }}
path: ./coverage.xml
Expand Down Expand Up @@ -139,9 +139,113 @@ jobs:
run: |
uv run poe test-slow

release-preflight:
name: Release Preflight
needs: test-slow
runs-on: ubuntu-latest
if:
${{ success() && (github.ref == 'refs/heads/main' || github.event_name ==
'pull_request') }}
# Least privilege: this job checks out and runs untrusted PR code
# (scripts/release_preflight.py), so it must never hold a write-scoped token.
# Posting the report comment is handled by the separate comment-preflight
# job below, which never executes PR code.
permissions:
contents: read
steps:
- name: Checkout 🛎
uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Run release preflight report
id: preflight
run: |
set +e
python3 scripts/release_preflight.py --strict --output release-preflight-report.md
Comment on lines +161 to +165
Comment on lines +164 to +165
exit_code=$?
echo "exit_code=$exit_code" >> "$GITHUB_OUTPUT"
exit 0

- name: Upload preflight artifact
uses: actions/upload-artifact@v7
with:
name: release-preflight-report
path: release-preflight-report.md
if-no-files-found: error

- name: Fail on preflight violations
if: steps.preflight.outputs.exit_code != '0'
run: |
echo "Release preflight failed with exit code ${{ steps.preflight.outputs.exit_code }}."
exit 1

comment-preflight:
name: Comment Preflight Report
needs: release-preflight
runs-on: ubuntu-latest
# Isolated commenting job: it does NOT check out or execute any PR code, it
# only downloads the report artifact and posts it. This is the only job that
# holds a write-scoped token, and it is gated to same-repo PRs (fork PRs
# receive a read-only token from GitHub regardless). always() lets the
# comment post even when the preflight check fails upstream.
if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
permissions:
pull-requests: write
steps:
- name: Download preflight artifact
uses: actions/download-artifact@v8
continue-on-error: true
with:
name: release-preflight-report

- name: Comment preflight report on PR
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
const path = 'release-preflight-report.md';
const marker = '<!-- release-preflight-report -->';
const report = fs.existsSync(path)
? fs.readFileSync(path, 'utf8')
: 'Preflight report file was not generated.';
const body = `${marker}\n## Release Preflight\n\n\
_Automated check that complements semantic-release changelog generation._\n\n\
\`\`\`markdown\n${report}\n\`\`\``;

const { owner, repo } = context.repo;
const issue_number = context.issue.number;

const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number,
per_page: 100,
});

const existing = comments.find(
(c) => c.user?.type === 'Bot' && c.body?.includes(marker),
);

if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}

release:
name: Create Release package
needs: test-slow
needs: release-preflight
if: success() && github.ref == 'refs/heads/main' &&
!contains(github.event.head_commit.message, '[skip release]')
runs-on: ubuntu-latest
Expand Down Expand Up @@ -169,7 +273,7 @@ jobs:
install-args: "--extra report --extra rna --extra tabpfn --extra tabicl"

- name: Python Semantic Release
uses: python-semantic-release/python-semantic-release@v10.2.0
uses: python-semantic-release/python-semantic-release@2896129e02bb7809d2cf0c1b8e9e795ee27acbcf # v10.2.0
id: release
with:
github_token: ${{ secrets.PAT_RELEASE_PIPELINE }}
Expand Down Expand Up @@ -212,16 +316,16 @@ jobs:
path: dist

- name: Upload package to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
packages-dir: dist/

publish-pypi:
name: Publish to PyPI
needs: release
if: needs.release.outputs.released == 'true'
needs: [release, test-pypi-publish]
if: needs.release.outputs.released == 'true' && needs.test-pypi-publish.result == 'success'
environment:
name: pypi
url: https://pypi.org/project/mother-ml/
Expand All @@ -236,12 +340,12 @@ jobs:
path: dist/

- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
with:
packages-dir: dist/

build-mkdocs:
name: Build MkDocs
build-docs:
name: Build Docs
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -267,17 +371,16 @@ jobs:
install-args: "--group docs"

- name: Build docs
working-directory: mkdocs
run: uv run mkdocs build
run: uv run zensical build

- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@v4
with:
path: mkdocs/site/
path: site/

deploy-mkdocs:
deploy-docs:
name: Publish Docs
needs: build-mkdocs
needs: build-docs
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ ENV/
env.bak/
venv.bak/

# mkdocs documentation
mkdocs/site
# zensical documentation
site/

# mypy
.mypy_cache/
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
fail_fast: false
exclude: ^(docs/|examples/|tests/)
exclude: ^(examples/|test/)
Comment thread
SommerKai marked this conversation as resolved.
repos:
- repo: https://github.com/astral-sh/uv-pre-commit
rev: "0.11.2"
rev: "0.12.5"
hooks:
- id: uv-lock

Expand Down Expand Up @@ -71,7 +71,7 @@ repos:
entry: uv run poe docs-python-fences
pass_filenames: false
language: system
files: ^mkdocs/docs/.*\.md$
files: ^docs/.*\.md$
- repo: https://github.com/nbQA-dev/nbQA
rev: 1.9.1
hooks:
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Uses `uv` + `poe` (poethepoet). Run tasks with `uv run poe <task>`.
- **Style (check)**: `uv run poe check-style` = `check-sort-imports` (isort, black profile) + `check-format` (ruff format). Apply with `uv run poe style`.
- **Static analysis**: `uv run poe check-static-analysis` = `check-lint` (ruff, E+F) + `check-types` (mypy on `src`, strict: `disallow_untyped_defs`).
- **Lint autofix**: `uv run poe lint`.
- **Docs**: `uv run poe docs` (build) / `uv run poe serve-docs` (mkdocs serve from `mkdocs/`).
- **Docs**: `uv run poe docs` (build) / `uv run poe serve-docs` (zensical serve; config `zensical.toml` at repo root, content in `docs/`).
- **Pre-commit**: `uv run poe install-hook` then `uv run poe check-hook`.

Line length: ruff 120, pylint 100. Note: `CONTRIBUTING.md` references some task names (`poe test`, `test-acceptance`, `check-docs`) that do not exist in `pyproject.toml` — use the verified names above.
Expand Down
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# Mother-ML
# Mother-ML - A ML framework that takes care.

A ML framework that takes care.

Mother is a machine-learning framework for predicting properties from chemical molecules. The major features are:
Mother is a machine-learning framework for predicting properties from mainly chemical molecules. The major features are:

- 🔬 **SMILES** preprocessing
- 💾 Generating of **feature vectors** from molecules
- 📈 Grouping and cross-validation, based on chemical similarity
- 💻 Model Training: Standard catboost models, and feature selection methods
- 💻 Model Training: Standard models like catboost, lasso, or random forest, and custom models (e.g.: TabPFN), and feature selection methods
- 🚴 Training, cross-validation, and hyperparameter optimization of machine-learning models
- 🌀 Handling Gene expression data from transcriptomics experiments including different normalisation techniques
-~~Explainability analysis with *SHAP*~~ (Currently not supported, will be added in a later release)
Expand All @@ -16,7 +14,18 @@ Mother is a machine-learning framework for predicting properties from chemical m

Mother provides methods for each of these steps in the form of sklearn transformer objects. By that, all methods are designed to be easily accessible and usable in a modular way. The methods can be combined to ML workflows with [sklearn pipelines, column transformers, and feature unions](https://scikit-learn.org/dev/modules/compose.html).

All methods can be used as sklearn `transformer` or `estimator`. Combination with other methods, or own methods and models (e.g. using mother preprocessing with other model) is therefore straightforward. To be as compatible as possible, every transformer can be constructed using a dictionary containing the required parameters. However, to provide some convenience to the users, a settings class [MotherSettings](https://github.com/Bayer-Group/MotherML/blob/main/src/mother/settings.py). This class can be used to store all relevant settings for your ML project.
All methods can be used as sklearn `transformer` or `estimator`. Combination with other methods, or own methods and models (e.g. using mother preprocessing with other model) is therefore straightforward. To be as compatible as possible, every transformer can be constructed using a dictionary containing the required parameters. However, to provide some convenience to the users, a settings class [MotherSettings](https://github.com/Bayer-Group/MotherML/blob/main/src/mother/settings.py) is provided. This class can be used to store all relevant settings for your ML project.

## Why Mother?

Mother keeps the parts of a molecular ML workflow connected without requiring you to leave the scikit-learn ecosystem.

- **Tune an entire workflow from one place.** Mother model wrappers define their own Optuna search spaces, and `PipelineWithHyperparameterRooting`, `ColumnTransformerWithHyperparameterRooting`, and `FeatureUnionWithHyperparameterRooting` collect them across nested steps using familiar `step__parameter` names. You can therefore tune preprocessing, feature selection, and the final estimator together while retaining scikit-learn composition.
- **Exchange compatible transformers and estimators.** Preprocessing, molecular feature generation, feature selection, cross-validation grouping, and models follow scikit-learn's estimator and transformer interfaces. Mother components work in `Pipeline`, `ColumnTransformer`, and `FeatureUnion`, and can be combined with your own scikit-learn components.
- **Use consistent, analysis-ready outputs.** Components preserve pandas-friendly tabular data where appropriate. `predict_uncertainty(...)` exposes a common prediction and uncertainty schema across model backends, while `mother_cv(...)` returns fold-level predictions together with evaluation metadata for straightforward comparison and downstream analysis.
- **Evaluate chemical models more realistically.** Chemistry-aware grouping, including Tanimoto-similarity groups, makes it practical to use group-aware splits that better test generalisation to dissimilar compounds.
- **Choose models without rewriting the workflow.** The model registry discovers integrated model wrappers and presents a common interface for CatBoost, random forest, lasso, TabPFN when installed, and compatible custom models.
- **Make workflows reproducible and configurable.** `MotherSettings` keeps input, preprocessing, feature generation, cross-validation, model, and tuning configuration in one validated object that can be loaded from or written to YAML.

## Usage

Expand Down
28 changes: 28 additions & 0 deletions mkdocs/docs/Changelog.md → docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## v1.1.3 (2026-08-31)

### Bug Fixes

- Fix use count based fingerprints as default, including TabPFN precision handling and test updates
([#75](https://github.com/Bayer-Group/MotherML/pull/75),
[`74cac2ec`](https://github.com/Bayer-Group/MotherML/commit/74cac2ec0f93fa7f436c5fc6f4f5c8f711ae1a8a))

- (tabpfn) Restore upstream TabPFN precision handling with float32 for all operations


## v1.1.2 (2026-08-25)

### Bug Fixes

- Solving the `max_features` parameter not being correctly passed to the superclass
([#40](https://github.com/Bayer-Group/MotherML/pull/40),
[`4fd6869c`](https://github.com/Bayer-Group/MotherML/commit/4fd6869c3b3218cedf96060bcf4afe84ba70ece5))


## v1.1.1 (2026-08-21)

### Chores

- Update changelog for version 1.1.0 with bug fixes and new features
([`8a69fa24`](https://github.com/Bayer-Group/MotherML/commit/8a69fa246b449f257dacd93d0cbbd28b28090532))


## v1.1.0 (2026-08-20)

### Bug Fixes
Expand Down
File renamed without changes.
Loading
Loading