impregcalc 0.1.0__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.
Files changed (54) hide show
  1. impregcalc-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +27 -0
  2. impregcalc-0.1.0/.github/ISSUE_TEMPLATE/dataset.yml +27 -0
  3. impregcalc-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +19 -0
  4. impregcalc-0.1.0/.github/ISSUE_TEMPLATE/macos-gui.yml +53 -0
  5. impregcalc-0.1.0/.github/ISSUE_TEMPLATE/scientific-result.yml +26 -0
  6. impregcalc-0.1.0/.github/dependabot.yml +13 -0
  7. impregcalc-0.1.0/.github/workflows/ci.yml +173 -0
  8. impregcalc-0.1.0/.github/workflows/macos.yml +95 -0
  9. impregcalc-0.1.0/.github/workflows/publish.yml +69 -0
  10. impregcalc-0.1.0/.gitignore +13 -0
  11. impregcalc-0.1.0/CHANGELOG.md +16 -0
  12. impregcalc-0.1.0/CITATION.cff +16 -0
  13. impregcalc-0.1.0/CONTRIBUTING.md +41 -0
  14. impregcalc-0.1.0/LICENSE +22 -0
  15. impregcalc-0.1.0/PKG-INFO +212 -0
  16. impregcalc-0.1.0/README.md +148 -0
  17. impregcalc-0.1.0/SECURITY.md +8 -0
  18. impregcalc-0.1.0/assets/social-preview.png +0 -0
  19. impregcalc-0.1.0/docs/ci-security.md +31 -0
  20. impregcalc-0.1.0/docs/input-schema.md +29 -0
  21. impregcalc-0.1.0/docs/macos.md +63 -0
  22. impregcalc-0.1.0/docs/naming-audit.md +40 -0
  23. impregcalc-0.1.0/docs/scientific-basis.md +146 -0
  24. impregcalc-0.1.0/docs/validation.md +47 -0
  25. impregcalc-0.1.0/examples/co_ru_iwi.json +35 -0
  26. impregcalc-0.1.0/examples/nickel_oxide_wet.json +21 -0
  27. impregcalc-0.1.0/pyproject.toml +87 -0
  28. impregcalc-0.1.0/src/impregcalc/__init__.py +35 -0
  29. impregcalc-0.1.0/src/impregcalc/application/__init__.py +1 -0
  30. impregcalc-0.1.0/src/impregcalc/application/service.py +115 -0
  31. impregcalc-0.1.0/src/impregcalc/cli/__init__.py +5 -0
  32. impregcalc-0.1.0/src/impregcalc/cli/__main__.py +3 -0
  33. impregcalc-0.1.0/src/impregcalc/cli/main.py +90 -0
  34. impregcalc-0.1.0/src/impregcalc/core/__init__.py +1 -0
  35. impregcalc-0.1.0/src/impregcalc/core/calculator.py +307 -0
  36. impregcalc-0.1.0/src/impregcalc/core/errors.py +13 -0
  37. impregcalc-0.1.0/src/impregcalc/core/formula.py +201 -0
  38. impregcalc-0.1.0/src/impregcalc/core/models.py +224 -0
  39. impregcalc-0.1.0/src/impregcalc/gui/__init__.py +12 -0
  40. impregcalc-0.1.0/src/impregcalc/gui/__main__.py +3 -0
  41. impregcalc-0.1.0/src/impregcalc/gui/app.py +198 -0
  42. impregcalc-0.1.0/src/impregcalc/io/__init__.py +5 -0
  43. impregcalc-0.1.0/src/impregcalc/io/export.py +180 -0
  44. impregcalc-0.1.0/src/impregcalc/plotting/__init__.py +5 -0
  45. impregcalc-0.1.0/src/impregcalc/plotting/recipe.py +46 -0
  46. impregcalc-0.1.0/src/impregcalc/py.typed +1 -0
  47. impregcalc-0.1.0/tests/gui/test_gui_import.py +21 -0
  48. impregcalc-0.1.0/tests/gui_widget_smoke.py +24 -0
  49. impregcalc-0.1.0/tests/integration/test_cli.py +43 -0
  50. impregcalc-0.1.0/tests/integration/test_project_contracts.py +51 -0
  51. impregcalc-0.1.0/tests/integration/test_service_and_export.py +65 -0
  52. impregcalc-0.1.0/tests/macos/test_macos_gui_lifecycle.py +23 -0
  53. impregcalc-0.1.0/tests/unit/test_calculator.py +200 -0
  54. impregcalc-0.1.0/tests/unit/test_formula.py +36 -0
@@ -0,0 +1,27 @@
1
+ name: Bug report
2
+ description: Report reproducible software behavior that is not a scientific-definition question.
3
+ title: "[Bug]: "
4
+ labels: [bug]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: "Do not upload confidential or unpublished research data to this public issue."
9
+ - type: input
10
+ id: version
11
+ attributes:
12
+ label: ImpregCalc version
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: reproduce
17
+ attributes:
18
+ label: Minimal reproduction and full error output
19
+ validations:
20
+ required: true
21
+ - type: textarea
22
+ id: expected
23
+ attributes:
24
+ label: Expected behavior
25
+ validations:
26
+ required: true
27
+
@@ -0,0 +1,27 @@
1
+ name: Real dataset compatibility
2
+ description: Propose a public catalyst-preparation record for validation or compatibility.
3
+ title: "[Dataset]: "
4
+ labels: [dataset]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: "Only public, licensed data. Never attach unpublished or confidential laboratory records."
9
+ - type: input
10
+ id: doi
11
+ attributes:
12
+ label: DOI or stable public URL
13
+ validations:
14
+ required: true
15
+ - type: input
16
+ id: license
17
+ attributes:
18
+ label: Dataset license
19
+ validations:
20
+ required: true
21
+ - type: textarea
22
+ id: scope
23
+ attributes:
24
+ label: Files, checksum, and proposed validation scope
25
+ validations:
26
+ required: true
27
+
@@ -0,0 +1,19 @@
1
+ name: Feature request
2
+ description: Propose a focused preparation workflow or usability improvement.
3
+ title: "[Feature]: "
4
+ labels: [enhancement]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: "Do not include confidential research data. Scientific features need definitions and references."
9
+ - type: textarea
10
+ id: workflow
11
+ attributes:
12
+ label: Research workflow and current limitation
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: science
17
+ attributes:
18
+ label: Scientific definition, validity range, and reference
19
+
@@ -0,0 +1,53 @@
1
+ name: macOS or GUI issue
2
+ description: Report installation, Tkinter, window lifecycle, or backend behavior on macOS.
3
+ title: "[macOS/GUI]: "
4
+ labels: [macos, gui]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: "Do not post confidential data. Remove paths or environment values that reveal secrets."
9
+ - type: input
10
+ id: macos
11
+ attributes:
12
+ label: macOS version
13
+ validations:
14
+ required: true
15
+ - type: dropdown
16
+ id: architecture
17
+ attributes:
18
+ label: Architecture
19
+ options: [Apple Silicon, Intel]
20
+ validations:
21
+ required: true
22
+ - type: input
23
+ id: python
24
+ attributes:
25
+ label: Python version
26
+ validations:
27
+ required: true
28
+ - type: input
29
+ id: package
30
+ attributes:
31
+ label: ImpregCalc version
32
+ validations:
33
+ required: true
34
+ - type: input
35
+ id: gui
36
+ attributes:
37
+ label: Tk/Tcl version
38
+ description: Run `python -c "import tkinter; print(tkinter.TkVersion)"`.
39
+ validations:
40
+ required: true
41
+ - type: input
42
+ id: install
43
+ attributes:
44
+ label: Installation method
45
+ validations:
46
+ required: true
47
+ - type: textarea
48
+ id: traceback
49
+ attributes:
50
+ label: Full traceback or terminal output
51
+ validations:
52
+ required: true
53
+
@@ -0,0 +1,26 @@
1
+ name: Scientific result question
2
+ description: Ask about an equation, convention, unit, assumption, or numerical result.
3
+ title: "[Science]: "
4
+ labels: [scientific-question]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: "Use a minimal non-confidential example. Do not post unpublished or proprietary data."
9
+ - type: textarea
10
+ id: definition
11
+ attributes:
12
+ label: Loading definition, units, and assumptions
13
+ description: State target quantity and denominator explicitly.
14
+ validations:
15
+ required: true
16
+ - type: textarea
17
+ id: calculation
18
+ attributes:
19
+ label: Input and observed result
20
+ validations:
21
+ required: true
22
+ - type: input
23
+ id: reference
24
+ attributes:
25
+ label: Relevant publication or reference
26
+
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ open-pull-requests-limit: 5
8
+ - package-ecosystem: github-actions
9
+ directory: "/"
10
+ schedule:
11
+ interval: weekly
12
+ open-pull-requests-limit: 5
13
+
@@ -0,0 +1,173 @@
1
+ name: DGX CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: impregcalc-dgx-${{ github.event.pull_request.number || github.ref }}
15
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
16
+
17
+ jobs:
18
+ required:
19
+ name: DGX ARM64 / required
20
+ # Persistent research hardware may only execute trusted owner-authored code.
21
+ if: >-
22
+ github.event_name != 'pull_request' ||
23
+ (github.actor == github.repository_owner &&
24
+ github.event.pull_request.head.repo.full_name == github.repository)
25
+ runs-on: [self-hosted, Linux, ARM64, dgx-spark]
26
+ timeout-minutes: 60
27
+ env:
28
+ PIP_NO_CACHE_DIR: "1"
29
+ MPLBACKEND: Agg
30
+ IMPREGCALC_CI_VENV: impregcalc-ci-${{ github.run_id }}-${{ github.run_attempt }}
31
+ IMPREGCALC_WHEEL_VENV: impregcalc-wheel-${{ github.run_id }}-${{ github.run_attempt }}
32
+ IMPREGCALC_CI_OUTPUT: impregcalc-output-${{ github.run_id }}-${{ github.run_attempt }}
33
+ steps:
34
+ - name: Check out source
35
+ uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
36
+ with:
37
+ clean: true
38
+ fetch-depth: 0
39
+ persist-credentials: false
40
+ - name: Set up Python
41
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
42
+ with:
43
+ python-version: "3.13"
44
+ - name: Configure validated shared Tk and Xvfb runtime
45
+ env:
46
+ IMPREGCALC_GUI_RUNTIME: /opt/catalysttwin-actions/shared-gui-runtime
47
+ run: |
48
+ set -eu
49
+ runtime="$IMPREGCALC_GUI_RUNTIME"
50
+ bin_dir="$runtime/usr/bin"
51
+ lib_dir="$runtime/usr/lib/aarch64-linux-gnu"
52
+ tk_dir="$runtime/usr/share/tcltk/tk8.6"
53
+ test -d "$bin_dir"
54
+ test -d "$lib_dir"
55
+ test -d "$tk_dir"
56
+ export PATH="$bin_dir:$PATH"
57
+ export LD_LIBRARY_PATH="$lib_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
58
+ export TK_LIBRARY="$tk_dir"
59
+ printf '%s\n' "$bin_dir" >> "$GITHUB_PATH"
60
+ {
61
+ printf 'LD_LIBRARY_PATH=%s\n' "$LD_LIBRARY_PATH"
62
+ printf 'TK_LIBRARY=%s\n' "$TK_LIBRARY"
63
+ } >> "$GITHUB_ENV"
64
+ command -v Xvfb
65
+ command -v xvfb-run
66
+ python -c 'import tkinter; print(tkinter.TkVersion)'
67
+ - name: Create isolated environments
68
+ run: |
69
+ python -m venv "$RUNNER_TEMP/$IMPREGCALC_CI_VENV"
70
+ python -m venv "$RUNNER_TEMP/$IMPREGCALC_WHEEL_VENV"
71
+ mkdir -p "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT"
72
+ - name: Install project and development dependencies
73
+ run: |
74
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m pip install --upgrade pip
75
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m pip install -e ".[dev,plot]"
76
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m pip check
77
+ - name: Check formatting
78
+ run: |
79
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m ruff format --check .
80
+ - name: Lint
81
+ run: |
82
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m ruff check .
83
+ - name: Type check
84
+ run: |
85
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m mypy src
86
+ - name: Unit, scientific, integration, and import-isolation tests
87
+ run: |
88
+ "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" -m pytest
89
+ - name: CLI and example workflow
90
+ run: |
91
+ py="$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python"
92
+ "$py" -m impregcalc.cli formula 'Co(NO3)2·6H2O'
93
+ "$py" -m impregcalc.cli validate examples/co_ru_iwi.json
94
+ "$py" -m impregcalc.cli calculate examples/co_ru_iwi.json \
95
+ --output "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/recipe.xlsx" \
96
+ --plot "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/recipe.svg"
97
+ test -s "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/recipe.xlsx"
98
+ test -s "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/recipe.svg"
99
+ - name: Wired GUI calculation, export, close, and exit
100
+ run: |
101
+ xvfb-run -a "$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python" \
102
+ tests/gui_widget_smoke.py \
103
+ "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/gui-recipe.md"
104
+ test -s "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/gui-recipe.md"
105
+ - name: Build and validate distributions
106
+ run: |
107
+ py="$RUNNER_TEMP/$IMPREGCALC_CI_VENV/bin/python"
108
+ "$py" -m build
109
+ "$py" -m twine check dist/*
110
+ - name: Verify clean wheel without GUI or plotting dependencies
111
+ run: |
112
+ py="$RUNNER_TEMP/$IMPREGCALC_WHEEL_VENV/bin/python"
113
+ "$py" -m pip install --upgrade pip
114
+ "$py" -m pip install dist/*.whl
115
+ "$py" -m pip check
116
+ "$py" - <<'PY'
117
+ import importlib.metadata
118
+ import platform
119
+ import sys
120
+ import impregcalc
121
+
122
+ assert platform.machine().lower() in {"aarch64", "arm64"}
123
+ assert impregcalc.__version__ == importlib.metadata.version("impregcalc")
124
+ assert "tkinter" not in sys.modules
125
+ assert "matplotlib" not in sys.modules
126
+ print(platform.machine(), impregcalc.__version__, impregcalc.__file__)
127
+ PY
128
+ "$RUNNER_TEMP/$IMPREGCALC_WHEEL_VENV/bin/impregcalc" --help
129
+ "$RUNNER_TEMP/$IMPREGCALC_WHEEL_VENV/bin/impregcalc" calculate \
130
+ examples/co_ru_iwi.json \
131
+ --output "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/wheel-recipe.md"
132
+ xvfb-run -a "$py" tests/gui_widget_smoke.py \
133
+ "$RUNNER_TEMP/$IMPREGCALC_CI_OUTPUT/wheel-gui.md"
134
+ - name: Clean isolated files and verify checkout
135
+ if: always()
136
+ run: |
137
+ python - <<'PY'
138
+ import os
139
+ from pathlib import Path
140
+ import shutil
141
+
142
+ runner_temp = Path(os.environ["RUNNER_TEMP"]).resolve()
143
+ workspace = Path(os.environ["GITHUB_WORKSPACE"]).resolve()
144
+ for variable in (
145
+ "IMPREGCALC_CI_VENV",
146
+ "IMPREGCALC_WHEEL_VENV",
147
+ "IMPREGCALC_CI_OUTPUT",
148
+ ):
149
+ target = (runner_temp / os.environ[variable]).resolve()
150
+ if runner_temp not in target.parents:
151
+ raise RuntimeError(f"Refusing to clean outside runner temp: {target}")
152
+ shutil.rmtree(target, ignore_errors=True)
153
+ for relative in (
154
+ "build",
155
+ "dist",
156
+ ".mypy_cache",
157
+ ".pytest_cache",
158
+ ".ruff_cache",
159
+ ".coverage",
160
+ "htmlcov",
161
+ ):
162
+ target = (workspace / relative).resolve()
163
+ if workspace not in target.parents:
164
+ raise RuntimeError(f"Refusing to clean outside workspace: {target}")
165
+ if target.is_dir():
166
+ shutil.rmtree(target)
167
+ elif target.exists():
168
+ target.unlink()
169
+ for target in workspace.rglob("__pycache__"):
170
+ if workspace in target.resolve().parents:
171
+ shutil.rmtree(target)
172
+ PY
173
+ test -z "$(git status --porcelain)"
@@ -0,0 +1,95 @@
1
+ name: macOS GUI compatibility
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: impregcalc-macos-${{ github.event.pull_request.number || github.ref }}
15
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
16
+
17
+ jobs:
18
+ macos:
19
+ name: ${{ matrix.label }} / Python ${{ matrix.python }}
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ include:
24
+ - label: macos-15
25
+ python: "3.10"
26
+ architecture: arm64
27
+ - label: macos-15-intel
28
+ python: "3.13"
29
+ architecture: x86_64
30
+ runs-on: ${{ matrix.label }}
31
+ timeout-minutes: 35
32
+ env:
33
+ MPLBACKEND: Agg
34
+ steps:
35
+ - name: Check out source
36
+ uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
37
+ with:
38
+ persist-credentials: false
39
+ - name: Set up Python
40
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
41
+ with:
42
+ python-version: ${{ matrix.python }}
43
+ - name: Confirm OS, architecture, Tk, and absence of Qt
44
+ env:
45
+ EXPECTED_ARCH: ${{ matrix.architecture }}
46
+ run: |
47
+ test "$(uname -m)" = "$EXPECTED_ARCH"
48
+ sw_vers
49
+ python -c 'import platform, tkinter; print(platform.python_version(), tkinter.TkVersion)'
50
+ python - <<'PY'
51
+ import importlib.util
52
+ for name in ("PyQt5", "PyQt6", "PySide2", "PySide6"):
53
+ assert importlib.util.find_spec(name) is None, name
54
+ PY
55
+ - name: Install source in a virtual environment
56
+ run: |
57
+ python -m venv "$RUNNER_TEMP/impregcalc-macos"
58
+ "$RUNNER_TEMP/impregcalc-macos/bin/python" -m pip install --upgrade pip
59
+ "$RUNNER_TEMP/impregcalc-macos/bin/python" -m pip install -e ".[dev,plot]"
60
+ "$RUNNER_TEMP/impregcalc-macos/bin/python" -m pip check
61
+ - name: Scientific, CLI, and GUI-import tests
62
+ run: |
63
+ py="$RUNNER_TEMP/impregcalc-macos/bin/python"
64
+ "$py" -m pytest tests/unit tests/integration tests/gui
65
+ "$py" -m impregcalc.cli validate examples/co_ru_iwi.json
66
+ - name: Real Tk window workflow and normal process exit
67
+ run: |
68
+ py="$RUNNER_TEMP/impregcalc-macos/bin/python"
69
+ "$py" tests/gui_widget_smoke.py "$RUNNER_TEMP/macos-gui-recipe.md"
70
+ test -s "$RUNNER_TEMP/macos-gui-recipe.md"
71
+ - name: Explicit Agg plot backend and export
72
+ run: |
73
+ py="$RUNNER_TEMP/impregcalc-macos/bin/python"
74
+ "$py" -m impregcalc.cli calculate examples/co_ru_iwi.json \
75
+ --output "$RUNNER_TEMP/macos-recipe.xlsx" \
76
+ --plot "$RUNNER_TEMP/macos-recipe.pdf"
77
+ "$py" -c 'import matplotlib; assert "agg" in matplotlib.get_backend().lower()'
78
+ test -s "$RUNNER_TEMP/macos-recipe.xlsx"
79
+ test -s "$RUNNER_TEMP/macos-recipe.pdf"
80
+ - name: Build and clean-wheel installation
81
+ run: |
82
+ py="$RUNNER_TEMP/impregcalc-macos/bin/python"
83
+ "$py" -m build
84
+ "$py" -m twine check dist/*
85
+ python -m venv "$RUNNER_TEMP/impregcalc-wheel"
86
+ wheel_py="$RUNNER_TEMP/impregcalc-wheel/bin/python"
87
+ "$wheel_py" -m pip install dist/*.whl
88
+ "$wheel_py" -m pip check
89
+ "$wheel_py" -c 'import impregcalc, sys; assert "tkinter" not in sys.modules'
90
+ "$RUNNER_TEMP/impregcalc-wheel/bin/impregcalc" calculate \
91
+ examples/co_ru_iwi.json --output "$RUNNER_TEMP/wheel-recipe.md"
92
+ "$wheel_py" tests/gui_widget_smoke.py "$RUNNER_TEMP/wheel-gui.md"
93
+ test -s "$RUNNER_TEMP/wheel-recipe.md"
94
+ test -s "$RUNNER_TEMP/wheel-gui.md"
95
+
@@ -0,0 +1,69 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ if: github.event.release.prerelease == false
10
+ runs-on: ubuntu-24.04
11
+ permissions:
12
+ contents: read
13
+ steps:
14
+ - name: Check out tagged source
15
+ uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
16
+ with:
17
+ persist-credentials: false
18
+ - name: Set up Python
19
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
20
+ with:
21
+ python-version: "3.12"
22
+ - name: Build and verify tagged version
23
+ env:
24
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
25
+ run: |
26
+ python -m pip install --upgrade pip build twine
27
+ python -m build
28
+ python -m twine check dist/*
29
+ python -m venv /tmp/impregcalc-release-wheel
30
+ /tmp/impregcalc-release-wheel/bin/python -m pip install dist/*.whl
31
+ /tmp/impregcalc-release-wheel/bin/python -m pip check
32
+ /tmp/impregcalc-release-wheel/bin/python - <<'PY'
33
+ import importlib.metadata
34
+ import os
35
+ import sys
36
+ import impregcalc
37
+
38
+ expected = os.environ["RELEASE_TAG"].removeprefix("v")
39
+ assert impregcalc.__version__ == expected
40
+ assert importlib.metadata.version("impregcalc") == expected
41
+ assert "tkinter" not in sys.modules
42
+ PY
43
+ /tmp/impregcalc-release-wheel/bin/impregcalc --help
44
+ /tmp/impregcalc-release-wheel/bin/impregcalc calculate \
45
+ examples/co_ru_iwi.json --output /tmp/impregcalc-release-example.md
46
+ - name: Upload distributions
47
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
48
+ with:
49
+ name: python-package-distributions
50
+ path: dist/
51
+ if-no-files-found: error
52
+
53
+ publish:
54
+ needs: build
55
+ runs-on: ubuntu-24.04
56
+ environment:
57
+ name: pypi
58
+ url: https://pypi.org/p/impregcalc
59
+ permissions:
60
+ id-token: write
61
+ steps:
62
+ - name: Download distributions
63
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
64
+ with:
65
+ name: python-package-distributions
66
+ path: dist/
67
+ - name: Publish with Trusted Publishing
68
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
69
+
@@ -0,0 +1,13 @@
1
+ .venv/
2
+ build/
3
+ dist/
4
+ *.egg-info/
5
+ __pycache__/
6
+ *.py[cod]
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+ .DS_Store
13
+
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ All notable changes will be recorded here. ImpregCalc follows semantic versioning
4
+ while scientific definition corrections may appear in patch releases.
5
+
6
+ ## 0.1.0 — unreleased
7
+
8
+ - Initial elemental-metal, metal-oxide, and precursor loading engine.
9
+ - Final-catalyst and support-relative mass-balance conventions.
10
+ - Hydrate-dot formula parser and precursor assay correction.
11
+ - Co-impregnation, atomic-ratio promoter, IWI/wet liquid planning, and cycle splits.
12
+ - Python API, CLI, Tkinter GUI, JSON/Markdown/CSV/XLSX and figure export.
13
+
14
+ The conditions for 1.0.0 are not met. They require external-user experience,
15
+ definition-stable workflows, and suitable public experimental validation.
16
+
@@ -0,0 +1,16 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use ImpregCalc, please cite this software and the scientific references documented in the repository."
3
+ title: "ImpregCalc"
4
+ type: software
5
+ version: 0.1.0
6
+ authors:
7
+ - family-names: Kim
8
+ given-names: Hyun Dong
9
+ repository-code: "https://github.com/hdkim99/ImpregCalc"
10
+ url: "https://github.com/hdkim99/ImpregCalc"
11
+ license: MIT
12
+ keywords:
13
+ - catalysis
14
+ - catalyst preparation
15
+ - impregnation
16
+ - stoichiometry
@@ -0,0 +1,41 @@
1
+ # Contributing
2
+
3
+ Thank you for improving ImpregCalc. Do not put unpublished, proprietary,
4
+ export-controlled, or otherwise confidential research data in a public issue or pull
5
+ request.
6
+
7
+ ## Scientific changes
8
+
9
+ Every scientific-core change must state:
10
+
11
+ 1. the equation or definition and the convention it implements;
12
+ 2. every input/output unit and loading denominator;
13
+ 3. assumptions, validity range, and unsupported cases;
14
+ 4. an original publication, established textbook, or peer-reviewed review when the
15
+ change is not a direct dimensional/stoichiometric derivation;
16
+ 5. an independent numerical validation (hand calculation, literature benchmark, or
17
+ controlled synthetic benchmark);
18
+ 6. boundary and invalid-input behavior plus a regression test.
19
+
20
+ Do not add an undocumented coefficient, threshold, uncertainty, or confidence claim.
21
+ Do not infer model validity from R² alone.
22
+
23
+ ## GUI and plotting changes
24
+
25
+ Record the supported platform, dependency change, backend impact, macOS smoke result,
26
+ and proof that CLI/core imports remain GUI-independent. Do not add Qt without a
27
+ documented need, one binding only, clean-environment macOS lifecycle validation, and
28
+ explicit backend checks.
29
+
30
+ ## Local checks
31
+
32
+ ```bash
33
+ python -m pip install -e ".[dev,plot]"
34
+ ruff format --check .
35
+ ruff check .
36
+ mypy src
37
+ pytest
38
+ python -m build
39
+ twine check dist/*
40
+ ```
41
+
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hyun Dong Kim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+