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
87 changes: 87 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Release

on:
push:
branches: [ main, master ]
paths:
- 'pyproject.toml'

jobs:
check-version:
runs-on: ubuntu-latest
outputs:
version-changed: ${{ steps.version-check.outputs.changed }}
new-version: ${{ steps.version-check.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check if version changed
id: version-check
run: |
# Get current version from pyproject.toml
CURRENT_VERSION=$(grep -E '^version = ' pyproject.toml | sed 's/version = "//' | sed 's/"//')
echo "current-version=$CURRENT_VERSION" >> $GITHUB_OUTPUT

# Check if pyproject.toml was changed in this push
if git diff --name-only HEAD~1 HEAD | grep -q "pyproject.toml"; then
# Get previous version
PREVIOUS_VERSION=$(git show HEAD~1:pyproject.toml | grep -E '^version = ' | sed 's/version = "//' | sed 's/"//' || echo "")

if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "Version unchanged: $CURRENT_VERSION"
fi
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "pyproject.toml not changed"
fi

release:
needs: check-version
if: needs.check-version.outputs.version-changed == 'true'
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "latest"

- name: Set up Python
run: uv python install 3.11

- name: Install dependencies
run: |
uv sync --dev
uv add --dev build twine

- name: Run tests
run: |
uv run pytest --cov=mixsol

- name: Build package
run: |
uv run python -m build

- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ needs.check-version.outputs.new-version }}
release_name: Release v${{ needs.check-version.outputs.new-version }}
draft: false
prerelease: false

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
31 changes: 31 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12', '3.13', '3.14']

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "latest"

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --dev

- name: Run tests with pytest
run: uv run pytest --cov=mixsol
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ dmypy.json

# Pyre type checker
.pyre/

CLAUDE.md
.ruff_cache/
69 changes: 32 additions & 37 deletions Example Notebooks/Powder Weighing.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,26 @@
"outputs": [],
"source": [
"powders = [\n",
" mx.Powder('Cs_I'), #if only using elements, you can simply input the formula delimited by underscores\n",
" mx.Powder({'Pb':1, 'I':2}), #you can also use a dictionary to specify the components\n",
" mx.Powder('Pb_Br2'),\n",
" mx.Powder('Pb_Cl2'),\n",
" mx.Powder(\n",
" formula='MA_I', #you can have components that are not element (like methylammonium/MA here), but then the molar mass must be specified\n",
" molar_mass=mx.calculate_molar_mass('C_H6_N_I'), #molar mass can either be given as a float value, or the helper function can take an elemental formula (as string or dict) and calculate the molar mass\n",
" alias='MAI', #you can also give an alias for the powder - this just changes the string representation of the powder when printed\n",
" \"Cs_I\"\n",
" ), # if only using elements, you can simply input the formula delimited by underscores\n",
" mx.Powder(\n",
" {\"Pb\": 1, \"I\": 2}\n",
" ), # you can also use a dictionary to specify the components\n",
" mx.Powder(\"Pb_Br2\"),\n",
" mx.Powder(\"Pb_Cl2\"),\n",
" mx.Powder(\n",
" formula=\"MA_I\", # you can have components that are not element (like methylammonium/MA here), but then the molar mass must be specified\n",
" molar_mass=mx.calculate_molar_mass(\n",
" \"C_H6_N_I\"\n",
" ), # molar mass can either be given as a float value, or the helper function can take an elemental formula (as string or dict) and calculate the molar mass\n",
" alias=\"MAI\", # you can also give an alias for the powder - this just changes the string representation of the powder when printed\n",
" ),\n",
" mx.Powder(\n",
" formula='FA_I',\n",
" molar_mass = mx.calculate_molar_mass('C_H5_N2_I'),\n",
" alias='FAI',\n",
" )\n",
" formula=\"FA_I\",\n",
" molar_mass=mx.calculate_molar_mass(\"C_H5_N2_I\"),\n",
" alias=\"FAI\",\n",
" ),\n",
"]"
]
},
Expand All @@ -53,9 +59,7 @@
"metadata": {},
"outputs": [],
"source": [
"weigher = mx.Weigher(\n",
" powders=powders\n",
")"
"weigher = mx.Weigher(powders=powders)"
]
},
{
Expand All @@ -79,17 +83,17 @@
}
],
"source": [
"target=mx.Solution(\n",
" solutes='Cs0.05_FA0.8_MA0.15_Pb_I2.4_Br0.45_Cl0.15',\n",
" solvent='DMF9_DMSO1',\n",
" molarity=1\n",
"target = mx.Solution(\n",
" solutes=\"Cs0.05_FA0.8_MA0.15_Pb_I2.4_Br0.45_Cl0.15\",\n",
" solvent=\"DMF9_DMSO1\",\n",
" molarity=1,\n",
")\n",
"\n",
"masses = weigher.get_weights(\n",
" target,\n",
" volume=100e-6, #in L\n",
" volume=100e-6, # in L\n",
")\n",
"print(masses) #masses of each powder, in grams"
"print(masses) # masses of each powder, in grams"
]
},
{
Expand All @@ -114,9 +118,9 @@
],
"source": [
"result = weigher.weights_to_solution(\n",
" weights=masses, #the dictionary of masses we just created\n",
" volume=100e-6, #volume of solution (L) \n",
" solvent='DMF9_DMSO1', #solvent system\n",
" weights=masses, # the dictionary of masses we just created\n",
" volume=100e-6, # volume of solution (L)\n",
" solvent=\"DMF9_DMSO1\", # solvent system\n",
")\n",
"print(result)"
]
Expand All @@ -138,7 +142,7 @@
}
],
"source": [
"result == target #we made it back to our target solution!"
"result == target # we made it back to our target solution!"
]
},
{
Expand All @@ -165,10 +169,7 @@
],
"source": [
"result_fixedmolarity = weigher.weights_to_solution(\n",
" weights=masses,\n",
" volume=100e-6,\n",
" solvent='DMF9_DMSO1',\n",
" molarity=1\n",
" weights=masses, volume=100e-6, solvent=\"DMF9_DMSO1\", molarity=1\n",
")\n",
"print(result_fixedmolarity)"
]
Expand All @@ -188,10 +189,7 @@
],
"source": [
"result_singlecomponent = weigher.weights_to_solution(\n",
" weights=masses,\n",
" volume=100e-6,\n",
" solvent='DMF9_DMSO1',\n",
" molarity=\"Pb\"\n",
" weights=masses, volume=100e-6, solvent=\"DMF9_DMSO1\", molarity=\"Pb\"\n",
")\n",
"print(result_singlecomponent)"
]
Expand All @@ -211,10 +209,7 @@
],
"source": [
"result_multicomponent = weigher.weights_to_solution(\n",
" weights=masses,\n",
" volume=100e-6,\n",
" solvent='DMF9_DMSO1',\n",
" molarity=[\"I\", \"Br\", \"Cl\"]\n",
" weights=masses, volume=100e-6, solvent=\"DMF9_DMSO1\", molarity=[\"I\", \"Br\", \"Cl\"]\n",
")\n",
"print(result_multicomponent)"
]
Expand All @@ -236,7 +231,7 @@
}
],
"source": [
"result == result_singlecomponent == result_multicomponent == result_fixedmolarity #all methods give the same result!"
"result == result_singlecomponent == result_multicomponent == result_fixedmolarity # all methods give the same result!"
]
}
],
Expand Down
Loading