oxidmol 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oxidmol-0.1.1/.claude/commands/check.md +24 -0
- oxidmol-0.1.1/.github/workflows/CI.yml +92 -0
- oxidmol-0.1.1/.github/workflows/publish.yml +178 -0
- oxidmol-0.1.1/.github/workflows/release-plz.yml +47 -0
- oxidmol-0.1.1/.gitignore +47 -0
- oxidmol-0.1.1/.python-version +1 -0
- oxidmol-0.1.1/CHANGELOG.md +5 -0
- oxidmol-0.1.1/CLAUDE.md +75 -0
- oxidmol-0.1.1/Cargo.lock +1793 -0
- oxidmol-0.1.1/Cargo.toml +32 -0
- oxidmol-0.1.1/PKG-INFO +46 -0
- oxidmol-0.1.1/README.md +24 -0
- oxidmol-0.1.1/cliff.toml +33 -0
- oxidmol-0.1.1/pyproject.toml +153 -0
- oxidmol-0.1.1/python/oxidmol/__init__.py +7 -0
- oxidmol-0.1.1/python/oxidmol/app.py +16 -0
- oxidmol-0.1.1/python/oxidmol/dsl/__init__.py +0 -0
- oxidmol-0.1.1/python/oxidmol/dsl/commands.py +16 -0
- oxidmol-0.1.1/python/oxidmol/dsl/grammar.py +33 -0
- oxidmol-0.1.1/python/oxidmol/dsl/transformer.py +24 -0
- oxidmol-0.1.1/python/oxidmol/lsd/__init__.pyi +32 -0
- oxidmol-0.1.1/python/oxidmol/lsd/py.typed +0 -0
- oxidmol-0.1.1/python/oxidmol/settings.py +134 -0
- oxidmol-0.1.1/python/oxidmol/tests/__init__.py +0 -0
- oxidmol-0.1.1/python/oxidmol/tests/test_bindings.py +19 -0
- oxidmol-0.1.1/python/oxidmol/tests/test_scene_widget.py +200 -0
- oxidmol-0.1.1/python/oxidmol/tests/test_ui.py +46 -0
- oxidmol-0.1.1/python/oxidmol/tests/utils/conftest.py +12 -0
- oxidmol-0.1.1/python/oxidmol/tests/utils/test_cache.py +118 -0
- oxidmol-0.1.1/python/oxidmol/tests/utils/test_fetch.py +135 -0
- oxidmol-0.1.1/python/oxidmol/tests/utils/test_loading.py +44 -0
- oxidmol-0.1.1/python/oxidmol/ui/__init__.py +0 -0
- oxidmol-0.1.1/python/oxidmol/ui/command_bar.py +66 -0
- oxidmol-0.1.1/python/oxidmol/ui/main_window.py +109 -0
- oxidmol-0.1.1/python/oxidmol/ui/menu/__init__.py +4 -0
- oxidmol-0.1.1/python/oxidmol/ui/menu/menu_bar.py +238 -0
- oxidmol-0.1.1/python/oxidmol/ui/menu/tool_bar.py +114 -0
- oxidmol-0.1.1/python/oxidmol/ui/object_panel.py +117 -0
- oxidmol-0.1.1/python/oxidmol/ui/scene.py +174 -0
- oxidmol-0.1.1/python/oxidmol/ui/theme.py +175 -0
- oxidmol-0.1.1/python/oxidmol/utils/__init__.py +0 -0
- oxidmol-0.1.1/python/oxidmol/utils/cache.py +89 -0
- oxidmol-0.1.1/python/oxidmol/utils/fetch.py +152 -0
- oxidmol-0.1.1/python/oxidmol/utils/loading.py +47 -0
- oxidmol-0.1.1/release-plz.toml +9 -0
- oxidmol-0.1.1/src/core/element.rs +519 -0
- oxidmol-0.1.1/src/core/mesh_builder.rs +212 -0
- oxidmol-0.1.1/src/core/molecule.rs +323 -0
- oxidmol-0.1.1/src/core.rs +7 -0
- oxidmol-0.1.1/src/lib.rs +58 -0
- oxidmol-0.1.1/src/python/molecule.rs +46 -0
- oxidmol-0.1.1/src/python/renderer.rs +102 -0
- oxidmol-0.1.1/src/python.rs +5 -0
- oxidmol-0.1.1/src/renderer/camera.rs +146 -0
- oxidmol-0.1.1/src/renderer/camera_gpu.rs +37 -0
- oxidmol-0.1.1/src/renderer/depth_texture.rs +55 -0
- oxidmol-0.1.1/src/renderer/gpu_context.rs +87 -0
- oxidmol-0.1.1/src/renderer/pipeline.rs +258 -0
- oxidmol-0.1.1/src/renderer/scene.rs +281 -0
- oxidmol-0.1.1/src/renderer/scene_object.rs +35 -0
- oxidmol-0.1.1/src/renderer/scene_pipeline.rs +38 -0
- oxidmol-0.1.1/src/renderer/state.rs +72 -0
- oxidmol-0.1.1/src/renderer/test_support.rs +161 -0
- oxidmol-0.1.1/src/renderer.rs +16 -0
- oxidmol-0.1.1/src/shaders/shader.wgsl +43 -0
- oxidmol-0.1.1/src/utils/error.rs +113 -0
- oxidmol-0.1.1/src/utils/logging.rs +92 -0
- oxidmol-0.1.1/src/utils/qt_window.rs +120 -0
- oxidmol-0.1.1/src/utils.rs +7 -0
- oxidmol-0.1.1/tests/data/1crn.pdb +354 -0
- oxidmol-0.1.1/tests/data/minimal.cif +29 -0
- oxidmol-0.1.1/tests/data/minimal.pdb +8 -0
- oxidmol-0.1.1/uv.lock +635 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run every check that CI runs (Rust and Python), without the GPU and app launch steps
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run these from the repository root in the activated virtual environment and report the result of each one.
|
|
6
|
+
Do not stop at the first failure: run all of them, then summarize what failed and why.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
source .venv/bin/activate
|
|
10
|
+
cargo fmt -- --check
|
|
11
|
+
cargo clippy --all-targets -- -D warnings
|
|
12
|
+
cargo test
|
|
13
|
+
uv run --no-sync maturin develop
|
|
14
|
+
ruff format --check python/
|
|
15
|
+
ruff check python/
|
|
16
|
+
mypy python/
|
|
17
|
+
QT_QPA_PLATFORM=offscreen pytest -m "not gpu"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Notes:
|
|
21
|
+
- `cargo test` needs the activated `.venv`, otherwise it fails to link with `-lpython3.9`.
|
|
22
|
+
- GPU tests print `skipping: no GPU adapter available` and still pass on machines without a GPU.
|
|
23
|
+
Say so in the summary if you see it.
|
|
24
|
+
- Fix only what the user asked for. If a check fails for an unrelated reason, report it instead of fixing it.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Tests and lint. Wheels and the PyPI upload live in publish.yml, which calls this workflow first.
|
|
2
|
+
name: CI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- master
|
|
8
|
+
pull_request:
|
|
9
|
+
paths-ignore:
|
|
10
|
+
- '**.md'
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
workflow_call:
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
# a new push cancels the previous run on the same branch/PR (never cancel runs for tags)
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
CARGO_INCREMENTAL: 0
|
|
24
|
+
CARGO_TERM_COLOR: always
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
test:
|
|
28
|
+
name: Run Tests
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
timeout-minutes: 20
|
|
31
|
+
strategy:
|
|
32
|
+
matrix:
|
|
33
|
+
python-version: ['3.12']
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- name: Set up Rust
|
|
37
|
+
uses: dtolnay/rust-toolchain@stable
|
|
38
|
+
- name: Cache Rust build
|
|
39
|
+
uses: Swatinem/rust-cache@v2
|
|
40
|
+
- name: Set up Python
|
|
41
|
+
uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: ${{ matrix.python-version }}
|
|
44
|
+
- name: Install system dependencies
|
|
45
|
+
run: sudo apt-get install -y libegl1 libgles2 libdbus-1-3
|
|
46
|
+
- name: Install uv
|
|
47
|
+
uses: astral-sh/setup-uv@v5
|
|
48
|
+
with:
|
|
49
|
+
enable-cache: true
|
|
50
|
+
- name: Install dependencies
|
|
51
|
+
run: uv sync --group dev --no-install-project
|
|
52
|
+
- name: Run Rust tests
|
|
53
|
+
run: cargo test
|
|
54
|
+
- name: Build Python extension
|
|
55
|
+
run: uv run --no-sync maturin develop
|
|
56
|
+
- name: Run Python tests
|
|
57
|
+
run: uv run --no-sync pytest -m "not gpu"
|
|
58
|
+
env:
|
|
59
|
+
QT_QPA_PLATFORM: offscreen
|
|
60
|
+
|
|
61
|
+
lint:
|
|
62
|
+
name: Lint and Format Check
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
timeout-minutes: 15
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
- name: Set up Rust
|
|
68
|
+
uses: dtolnay/rust-toolchain@stable
|
|
69
|
+
with:
|
|
70
|
+
components: rustfmt, clippy
|
|
71
|
+
- name: Cache Rust build
|
|
72
|
+
uses: Swatinem/rust-cache@v2
|
|
73
|
+
- name: Set up Python
|
|
74
|
+
uses: actions/setup-python@v5
|
|
75
|
+
with:
|
|
76
|
+
python-version: '3.12'
|
|
77
|
+
- name: Install uv
|
|
78
|
+
uses: astral-sh/setup-uv@v5
|
|
79
|
+
with:
|
|
80
|
+
enable-cache: true
|
|
81
|
+
- name: Install Python dependencies
|
|
82
|
+
run: uv sync --group dev --no-install-project
|
|
83
|
+
- name: Check Rust formatting
|
|
84
|
+
run: cargo fmt -- --check
|
|
85
|
+
- name: Run Clippy
|
|
86
|
+
run: cargo clippy --all-targets -- -D warnings
|
|
87
|
+
- name: Check Python formatting
|
|
88
|
+
run: uv run --no-sync ruff format --check python/
|
|
89
|
+
- name: Run Python linting
|
|
90
|
+
run: uv run --no-sync ruff check python/
|
|
91
|
+
- name: Run mypy
|
|
92
|
+
run: uv run --no-sync mypy python/
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Builds the wheels and the sdist and uploads them to PyPI.
|
|
2
|
+
# Runs for version tags (created by release-plz) and manually; a manual run builds everything but never uploads.
|
|
3
|
+
name: Publish
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- 'v[0-9]*'
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
# never cancel a release that is running
|
|
15
|
+
concurrency:
|
|
16
|
+
group: release-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
CARGO_INCREMENTAL: 0
|
|
21
|
+
CARGO_TERM_COLOR: always
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
checks:
|
|
25
|
+
name: Checks
|
|
26
|
+
uses: ./.github/workflows/CI.yml
|
|
27
|
+
|
|
28
|
+
linux:
|
|
29
|
+
name: Wheels (manylinux ${{ matrix.platform.target }})
|
|
30
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
31
|
+
timeout-minutes: 30
|
|
32
|
+
needs: [checks]
|
|
33
|
+
strategy:
|
|
34
|
+
matrix:
|
|
35
|
+
platform:
|
|
36
|
+
- runner: ubuntu-22.04
|
|
37
|
+
target: x86_64
|
|
38
|
+
- runner: ubuntu-22.04
|
|
39
|
+
target: aarch64
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: '3.12'
|
|
45
|
+
- name: Build wheels
|
|
46
|
+
uses: PyO3/maturin-action@v1
|
|
47
|
+
with:
|
|
48
|
+
target: ${{ matrix.platform.target }}
|
|
49
|
+
args: --release --out dist
|
|
50
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
51
|
+
manylinux: auto
|
|
52
|
+
- name: Upload wheels
|
|
53
|
+
uses: actions/upload-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: wheels-linux-${{ matrix.platform.target }}
|
|
56
|
+
path: dist
|
|
57
|
+
|
|
58
|
+
musllinux:
|
|
59
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
60
|
+
timeout-minutes: 30
|
|
61
|
+
needs: [checks]
|
|
62
|
+
strategy:
|
|
63
|
+
matrix:
|
|
64
|
+
platform:
|
|
65
|
+
- runner: ubuntu-22.04
|
|
66
|
+
target: x86_64
|
|
67
|
+
- runner: ubuntu-22.04
|
|
68
|
+
target: aarch64
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
- uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: '3.12'
|
|
74
|
+
- name: Build wheels
|
|
75
|
+
uses: PyO3/maturin-action@v1
|
|
76
|
+
with:
|
|
77
|
+
target: ${{ matrix.platform.target }}
|
|
78
|
+
args: --release --out dist
|
|
79
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
80
|
+
manylinux: musllinux_1_2
|
|
81
|
+
- name: Upload wheels
|
|
82
|
+
uses: actions/upload-artifact@v4
|
|
83
|
+
with:
|
|
84
|
+
name: wheels-musllinux-${{ matrix.platform.target }}
|
|
85
|
+
path: dist
|
|
86
|
+
|
|
87
|
+
windows:
|
|
88
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
89
|
+
timeout-minutes: 30
|
|
90
|
+
needs: [checks]
|
|
91
|
+
strategy:
|
|
92
|
+
matrix:
|
|
93
|
+
platform:
|
|
94
|
+
- runner: windows-latest
|
|
95
|
+
target: x64
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/checkout@v4
|
|
98
|
+
- uses: actions/setup-python@v5
|
|
99
|
+
with:
|
|
100
|
+
python-version: '3.12'
|
|
101
|
+
architecture: ${{ matrix.platform.target }}
|
|
102
|
+
- name: Build wheels
|
|
103
|
+
uses: PyO3/maturin-action@v1
|
|
104
|
+
with:
|
|
105
|
+
target: ${{ matrix.platform.target }}
|
|
106
|
+
args: --release --out dist
|
|
107
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
108
|
+
- name: Upload wheels
|
|
109
|
+
uses: actions/upload-artifact@v4
|
|
110
|
+
with:
|
|
111
|
+
name: wheels-windows-${{ matrix.platform.target }}
|
|
112
|
+
path: dist
|
|
113
|
+
|
|
114
|
+
macos:
|
|
115
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
116
|
+
timeout-minutes: 30
|
|
117
|
+
needs: [checks]
|
|
118
|
+
strategy:
|
|
119
|
+
matrix:
|
|
120
|
+
platform:
|
|
121
|
+
- runner: macos-14
|
|
122
|
+
target: aarch64
|
|
123
|
+
- runner: macos-14
|
|
124
|
+
target: x86_64
|
|
125
|
+
steps:
|
|
126
|
+
- uses: actions/checkout@v4
|
|
127
|
+
- uses: actions/setup-python@v5
|
|
128
|
+
with:
|
|
129
|
+
python-version: '3.12'
|
|
130
|
+
- name: Build wheels
|
|
131
|
+
uses: PyO3/maturin-action@v1
|
|
132
|
+
with:
|
|
133
|
+
target: ${{ matrix.platform.target }}
|
|
134
|
+
args: --release --out dist
|
|
135
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
136
|
+
- name: Upload wheels
|
|
137
|
+
uses: actions/upload-artifact@v4
|
|
138
|
+
with:
|
|
139
|
+
name: wheels-macos-${{ matrix.platform.target }}
|
|
140
|
+
path: dist
|
|
141
|
+
|
|
142
|
+
sdist:
|
|
143
|
+
name: Build sdist
|
|
144
|
+
runs-on: ubuntu-latest
|
|
145
|
+
timeout-minutes: 10
|
|
146
|
+
needs: [checks]
|
|
147
|
+
steps:
|
|
148
|
+
- uses: actions/checkout@v4
|
|
149
|
+
- name: Build sdist
|
|
150
|
+
uses: PyO3/maturin-action@v1
|
|
151
|
+
with:
|
|
152
|
+
command: sdist
|
|
153
|
+
args: --out dist
|
|
154
|
+
- name: Upload sdist
|
|
155
|
+
uses: actions/upload-artifact@v4
|
|
156
|
+
with:
|
|
157
|
+
name: sdist
|
|
158
|
+
path: dist/*.tar.gz
|
|
159
|
+
|
|
160
|
+
publish-pypi:
|
|
161
|
+
name: Publish to PyPI
|
|
162
|
+
runs-on: ubuntu-latest
|
|
163
|
+
timeout-minutes: 10
|
|
164
|
+
needs: [linux, musllinux, windows, macos, sdist]
|
|
165
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
166
|
+
environment:
|
|
167
|
+
name: pypi
|
|
168
|
+
url: https://pypi.org/p/oxidmol
|
|
169
|
+
permissions:
|
|
170
|
+
id-token: write
|
|
171
|
+
steps:
|
|
172
|
+
- name: Download all artifacts
|
|
173
|
+
uses: actions/download-artifact@v4
|
|
174
|
+
with:
|
|
175
|
+
path: dist
|
|
176
|
+
merge-multiple: true
|
|
177
|
+
- name: Publish to PyPI
|
|
178
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release-pr:
|
|
9
|
+
name: Create release PR
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
timeout-minutes: 10
|
|
12
|
+
concurrency:
|
|
13
|
+
group: release-plz-pr
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
pull-requests: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
23
|
+
- uses: release-plz/action@v0.5
|
|
24
|
+
with:
|
|
25
|
+
command: release-pr
|
|
26
|
+
env:
|
|
27
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN || secrets.GITHUB_TOKEN }}
|
|
28
|
+
|
|
29
|
+
release:
|
|
30
|
+
name: Create tag and GitHub release
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
timeout-minutes: 10
|
|
33
|
+
concurrency:
|
|
34
|
+
group: release-plz-release
|
|
35
|
+
cancel-in-progress: false
|
|
36
|
+
permissions:
|
|
37
|
+
contents: write
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
with:
|
|
41
|
+
fetch-depth: 0
|
|
42
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
43
|
+
- uses: release-plz/action@v0.5
|
|
44
|
+
with:
|
|
45
|
+
command: release
|
|
46
|
+
env:
|
|
47
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN || secrets.GITHUB_TOKEN }}
|
oxidmol-0.1.1/.gitignore
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Generated by Cargo
|
|
2
|
+
# will have compiled files and executables
|
|
3
|
+
debug
|
|
4
|
+
target
|
|
5
|
+
|
|
6
|
+
# These are backup files generated by rustfmt
|
|
7
|
+
**/*.rs.bk
|
|
8
|
+
|
|
9
|
+
# Generated by cargo mutants
|
|
10
|
+
# Contains mutation testing data
|
|
11
|
+
**/mutants.out*/
|
|
12
|
+
|
|
13
|
+
# RustRover
|
|
14
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
15
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
16
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
17
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
18
|
+
#.idea/
|
|
19
|
+
|
|
20
|
+
*.local
|
|
21
|
+
|
|
22
|
+
**/.env*
|
|
23
|
+
|
|
24
|
+
# intellij
|
|
25
|
+
**/.idea
|
|
26
|
+
|
|
27
|
+
# python
|
|
28
|
+
**/venv
|
|
29
|
+
**/__pycache__
|
|
30
|
+
**/*.pyc
|
|
31
|
+
**/*.egg-info
|
|
32
|
+
build/
|
|
33
|
+
.venv/
|
|
34
|
+
|
|
35
|
+
# pyright
|
|
36
|
+
pyrightconfig*.json
|
|
37
|
+
|
|
38
|
+
# mac
|
|
39
|
+
.DS_Store
|
|
40
|
+
target/
|
|
41
|
+
|
|
42
|
+
# unix like
|
|
43
|
+
*.so
|
|
44
|
+
|
|
45
|
+
# vscode
|
|
46
|
+
.vscode/
|
|
47
|
+
node_modules/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
oxidmol-0.1.1/CLAUDE.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# OxidMol: working notes for Claude
|
|
2
|
+
|
|
3
|
+
A PyMOL-inspired molecule viewer. The renderer is written in Rust on wgpu and exposed to Python through PyO3 as the module `oxidmol.lsd`; the UI is PySide6.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
source .venv/bin/activate # REQUIRED before cargo test, see "Pitfalls"
|
|
9
|
+
uv sync --group dev --no-install-project # dependencies without building Rust (same as CI)
|
|
10
|
+
uv run --no-sync maturin develop # build the extension into .venv (after every Rust change)
|
|
11
|
+
|
|
12
|
+
cargo fmt -- --check
|
|
13
|
+
cargo clippy --all-targets -- -D warnings # warnings are errors in CI
|
|
14
|
+
cargo test # Rust tests, including the GPU tests
|
|
15
|
+
|
|
16
|
+
ruff format --check python/ && ruff check python/ && mypy python/
|
|
17
|
+
QT_QPA_PLATFORM=offscreen pytest -m "not gpu" # what CI runs
|
|
18
|
+
pytest -m gpu # needs a display and a GPU
|
|
19
|
+
|
|
20
|
+
oxidmol # run the app (RUST_LOG=warn hides the naga/wgpu debug noise)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`/check` runs all of the above except the GPU and app launch steps. Run it before finishing a task: CI fails on any of them.
|
|
24
|
+
|
|
25
|
+
## Layout
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
src/
|
|
29
|
+
lib.rs PyO3 module `lsd`, logging setup
|
|
30
|
+
core/ Molecule, Chain/Residue/Atom, FlatAtom, sphere mesh; PDB/mmCIF loading (pdbtbx)
|
|
31
|
+
renderer/
|
|
32
|
+
state.rs State = GpuContext (window + surface) + Scene
|
|
33
|
+
gpu_context.rs instance/surface/adapter/device; everything returns Result<_, WgpuError>
|
|
34
|
+
scene.rs Scene: camera, pipeline, depth, objects; render() into any TextureView
|
|
35
|
+
pipeline.rs PipelineBuilder (takes the shader as a WGSL string)
|
|
36
|
+
scene_pipeline.rs builds the main pipeline; the shader is embedded with include_str!
|
|
37
|
+
test_support.rs (tests only) windowless device, pixel readback, validation error scope
|
|
38
|
+
python/ PyO3 wrappers: WgpuRenderer, PyMolecule
|
|
39
|
+
utils/ errors, qt_window.rs (QWidget.winId() -> raw-window-handle), logging
|
|
40
|
+
shaders/shader.wgsl
|
|
41
|
+
python/oxidmol/
|
|
42
|
+
app.py, settings.py
|
|
43
|
+
ui/ main_window, scene (WgpuWidget), object_panel, command_bar, menu/, theme.py
|
|
44
|
+
dsl/ command grammar (lark) and transformer
|
|
45
|
+
utils/ loading, cache, fetch
|
|
46
|
+
lsd/__init__.pyi type stubs for the Rust module
|
|
47
|
+
tests/data/ PDB/CIF files used by tests
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Pitfalls
|
|
51
|
+
|
|
52
|
+
- **`cargo test` does not link without the `.venv` activated** (`-lpython3.9`, it picks up Xcode's Python). Always `source .venv/bin/activate` first.
|
|
53
|
+
- **Rebuild with `maturin develop` after every Rust change**, otherwise the Python tests and the app use the old extension.
|
|
54
|
+
- **wgpu 30 requires a display handle on the instance**, even on Metal (`MissingDisplayHandle` otherwise). It is passed through `QtDisplayHandle`.
|
|
55
|
+
- **Use the `directx` projection, not `vulkan`.** The wgpu NDC is Z in [0, 1] with Y up; `vulkan` flips the image. There is no OpenGL-to-wgpu matrix any more.
|
|
56
|
+
- **GPU tests are skipped silently when there is no adapter, and a skip is a pass.** `OXIDMOL_REQUIRE_GPU=1` turns the skip into a failure. CI runners most likely have no GPU.
|
|
57
|
+
- **The windowless GPU tests do not cover the window.** `GpuContext` and the surface are only checked by launching the app and by the `gpu`-marked widget test.
|
|
58
|
+
- **Renderer errors are `RuntimeError`, not panics.** Catch `Exception` in Python, not `BaseException`.
|
|
59
|
+
- **Linux: only X11/XWayland.** Native Wayland is not supported yet. Manual testing so far was done on macOS only; Linux and Windows are not tested by hand.
|
|
60
|
+
- **PySide6 is capped at `<6.12`** because 6.12 has no wheels for macOS 13. Do not upgrade it without checking that the platform support has changed.
|
|
61
|
+
- **`approx` stays on 0.5** (0.6 is still a release candidate). `pollster` was replaced with `tokio` (feature `rt`).
|
|
62
|
+
- **Every molecule load adds an object instead of replacing the previous one.** Known, not fixed.
|
|
63
|
+
- **The extension uses the stable ABI (`pyo3/abi3-py312`)**: one wheel per platform works for every Python >= 3.12. After switching Python versions or build modes, delete stale `python/oxidmol/lsd.*.so` files: an old `lsd.cpython-*.so` is imported before `lsd.abi3.so`.
|
|
64
|
+
- **Releases**: release-plz runs in git-only mode (versions come from git tags, nothing goes to crates.io). A new `v*` tag starts `publish.yml`: it re-runs `CI.yml` through `workflow_call`, builds the wheels and uploads them to PyPI.
|
|
65
|
+
- Workflows: `CI.yml` (tests and lint on push and PR, also called by `publish.yml`), `publish.yml` (wheels, sdist and PyPI upload for tags; a manual run builds but never uploads), `release-plz.yml` (version PRs, tags). They were generated by `maturin generate-ci` once and are now edited by hand, do not regenerate them.
|
|
66
|
+
- The README and the module description in `lib.rs` say "PyQt6" although the project uses PySide6 (not fixed).
|
|
67
|
+
|
|
68
|
+
## Conventions
|
|
69
|
+
|
|
70
|
+
- Rust 2021, `cargo fmt`, no clippy warnings. Use a targeted `#[allow(dead_code)]` for intentionally unused code (the idiom already exists in the project).
|
|
71
|
+
- `unsafe` needs a `SAFETY:` comment that states the guarantee.
|
|
72
|
+
- Python: ruff (line length 120, rule set in `pyproject.toml`), strict-like mypy (`disallow_untyped_defs`); type the Qt event arguments (`QShowEvent` etc.).
|
|
73
|
+
- UI: styles live only in `ui/theme.py` (palette plus one `STYLESHEET`). Widgets get an `objectName` and no inline QSS. The exception is the per-object dot color in `object_panel.py`, which is dynamic. Get the monospace font from `theme.mono_font()`, never by family name.
|
|
74
|
+
- Tests: Rust tests sit next to the code (`#[cfg(test)]`); Python tests are in `python/oxidmol/tests` with the `ui` and `gpu` markers declared in `pyproject.toml`. Check a new test against a deliberate breakage: break the code temporarily and make sure the test fails.
|
|
75
|
+
- Commits: `release-plz` and `git-cliff` build the changelog from conventional commits only (`feat:`, `fix:`, `refactor:`, `perf:` ...); other commits are filtered out (`filter_unconventional = true`). Do not commit unless asked.
|