masster 0.2.5__tar.gz → 0.3.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.

Potentially problematic release.


This version of masster might be problematic. Click here for more details.

Files changed (89) hide show
  1. masster-0.3.0/.github/workflows/publish.yml +174 -0
  2. masster-0.3.0/.github/workflows/security.yml +88 -0
  3. masster-0.3.0/.github/workflows/test.yml +164 -0
  4. {masster-0.2.5 → masster-0.3.0}/.gitignore +210 -210
  5. masster-0.3.0/.pre-commit-config.yaml +96 -0
  6. {masster-0.2.5 → masster-0.3.0}/LICENSE +661 -661
  7. {masster-0.2.5 → masster-0.3.0}/Makefile +76 -76
  8. {masster-0.2.5 → masster-0.3.0}/PKG-INFO +15 -10
  9. {masster-0.2.5 → masster-0.3.0}/README.md +62 -58
  10. {masster-0.2.5 → masster-0.3.0}/TESTING.md +243 -243
  11. {masster-0.2.5 → masster-0.3.0}/demo/example_batch_process.py +190 -190
  12. {masster-0.2.5 → masster-0.3.0}/demo/example_sample_process.py +24 -24
  13. {masster-0.2.5 → masster-0.3.0}/pyproject.toml +189 -188
  14. {masster-0.2.5 → masster-0.3.0}/src/masster/__init__.py +27 -27
  15. {masster-0.2.5 → masster-0.3.0}/src/masster/_version.py +17 -17
  16. {masster-0.2.5 → masster-0.3.0}/src/masster/chromatogram.py +497 -503
  17. masster-0.3.0/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.featureXML +199787 -0
  18. masster-0.3.0/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.sample5 +0 -0
  19. {masster-0.2.5 → masster-0.3.0}/src/masster/logger.py +318 -244
  20. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/__init__.py +9 -9
  21. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/defaults/__init__.py +15 -15
  22. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/defaults/find_adducts_def.py +325 -325
  23. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/defaults/find_features_def.py +366 -366
  24. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/defaults/find_ms2_def.py +285 -285
  25. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/defaults/get_spectrum_def.py +314 -318
  26. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/defaults/sample_def.py +374 -378
  27. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/h5.py +1321 -1297
  28. masster-0.3.0/src/masster/sample/helpers.py +833 -0
  29. masster-0.3.0/src/masster/sample/lib.py +762 -0
  30. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/load.py +1220 -1187
  31. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/parameters.py +131 -131
  32. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/plot.py +1610 -1622
  33. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/processing.py +1402 -1416
  34. masster-0.3.0/src/masster/sample/quant.py +209 -0
  35. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/sample.py +391 -387
  36. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/sample5_schema.json +181 -181
  37. {masster-0.2.5 → masster-0.3.0}/src/masster/sample/save.py +737 -736
  38. masster-0.3.0/src/masster/sample/sciex.py +1213 -0
  39. {masster-0.2.5 → masster-0.3.0}/src/masster/spectrum.py +1287 -1319
  40. {masster-0.2.5 → masster-0.3.0}/src/masster/study/__init__.py +9 -9
  41. masster-0.3.0/src/masster/study/defaults/__init__.py +21 -0
  42. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/align_def.py +267 -267
  43. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/export_def.py +41 -40
  44. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/fill_chrom_def.py +264 -264
  45. masster-0.3.0/src/masster/study/defaults/fill_def.py +260 -0
  46. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/find_consensus_def.py +256 -256
  47. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/find_ms2_def.py +163 -163
  48. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/integrate_chrom_def.py +225 -225
  49. masster-0.3.0/src/masster/study/defaults/integrate_def.py +221 -0
  50. masster-0.3.0/src/masster/study/defaults/merge_def.py +256 -0
  51. {masster-0.2.5 → masster-0.3.0}/src/masster/study/defaults/study_def.py +272 -269
  52. masster-0.3.0/src/masster/study/export.py +674 -0
  53. masster-0.3.0/src/masster/study/h5.py +1398 -0
  54. masster-0.3.0/src/masster/study/helpers.py +1650 -0
  55. masster-0.3.0/src/masster/study/helpers_optimized.py +317 -0
  56. {masster-0.2.5 → masster-0.3.0}/src/masster/study/load.py +1201 -1078
  57. {masster-0.2.5 → masster-0.3.0}/src/masster/study/parameters.py +99 -99
  58. {masster-0.2.5 → masster-0.3.0}/src/masster/study/plot.py +632 -645
  59. {masster-0.2.5 → masster-0.3.0}/src/masster/study/processing.py +1057 -1046
  60. {masster-0.2.5 → masster-0.3.0}/src/masster/study/save.py +149 -134
  61. {masster-0.2.5 → masster-0.3.0}/src/masster/study/study.py +606 -522
  62. {masster-0.2.5 → masster-0.3.0}/src/masster/study/study5_schema.json +247 -241
  63. {masster-0.2.5 → masster-0.3.0}/tests/conftest.py +12 -12
  64. {masster-0.2.5 → masster-0.3.0}/tests/test_chromatogram.py +206 -193
  65. {masster-0.2.5 → masster-0.3.0}/tests/test_defaults.py +384 -384
  66. {masster-0.2.5 → masster-0.3.0}/tests/test_imports.py +76 -76
  67. {masster-0.2.5 → masster-0.3.0}/tests/test_integration.py +132 -132
  68. {masster-0.2.5 → masster-0.3.0}/tests/test_logger.py +268 -264
  69. {masster-0.2.5 → masster-0.3.0}/tests/test_parameters.py +109 -109
  70. {masster-0.2.5 → masster-0.3.0}/tests/test_sample.py +170 -170
  71. {masster-0.2.5 → masster-0.3.0}/tests/test_spectrum.py +143 -143
  72. {masster-0.2.5 → masster-0.3.0}/tests/test_study.py +133 -133
  73. {masster-0.2.5 → masster-0.3.0}/tests/test_version.py +51 -51
  74. {masster-0.2.5 → masster-0.3.0}/tox.ini +61 -61
  75. {masster-0.2.5 → masster-0.3.0}/uv.lock +2 -2
  76. masster-0.2.5/.github/workflows/publish.yml +0 -90
  77. masster-0.2.5/.github/workflows/security.yml +0 -43
  78. masster-0.2.5/.github/workflows/test.yml +0 -91
  79. masster-0.2.5/.pre-commit-config.yaml +0 -53
  80. masster-0.2.5/src/masster/sample/helpers.py +0 -364
  81. masster-0.2.5/src/masster/study/defaults/__init__.py +0 -19
  82. masster-0.2.5/src/masster/study/export.py +0 -287
  83. masster-0.2.5/src/masster/study/h5.py +0 -886
  84. masster-0.2.5/src/masster/study/helpers.py +0 -433
  85. {masster-0.2.5 → masster-0.3.0}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.mzML +0 -0
  86. {masster-0.2.5 → masster-0.3.0}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.timeseries.data +0 -0
  87. {masster-0.2.5 → masster-0.3.0}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff +0 -0
  88. {masster-0.2.5 → masster-0.3.0}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff.scan +0 -0
  89. {masster-0.2.5 → masster-0.3.0}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff2 +0 -0
@@ -0,0 +1,174 @@
1
+ name: Create release and Publish to PyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: 'Version to release (e.g., v1.0.0)'
8
+ required: true
9
+ type: string
10
+ test_pypi:
11
+ description: 'Publish to Test PyPI instead of PyPI'
12
+ required: false
13
+ default: false
14
+ type: boolean
15
+
16
+ jobs:
17
+ create-release:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.11"
28
+
29
+ - name: Update version in pyproject.toml
30
+ run: |
31
+ # Remove 'v' prefix if present
32
+ VERSION="${{ github.event.inputs.version }}"
33
+ VERSION=${VERSION#v}
34
+
35
+ # Update version in pyproject.toml
36
+ sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
37
+
38
+ # Verify the change
39
+ echo "Updated pyproject.toml version:"
40
+ grep "^version = " pyproject.toml
41
+
42
+ - name: Update version in _version.py
43
+ run: |
44
+ # Remove 'v' prefix if present
45
+ VERSION="${{ github.event.inputs.version }}"
46
+ VERSION=${VERSION#v}
47
+
48
+ # Update version in _version.py
49
+ sed -i "s/__version__ = \".*\"/__version__ = \"$VERSION\"/" src/masster/_version.py
50
+
51
+ # Verify the change
52
+ echo "Updated _version.py:"
53
+ grep "__version__ = " src/masster/_version.py
54
+
55
+ - name: Commit version updates
56
+ run: |
57
+ git config --local user.email "action@github.com"
58
+ git config --local user.name "GitHub Action"
59
+ git add pyproject.toml src/masster/_version.py
60
+ git commit -m "Update version to ${{ github.event.inputs.version }}" || echo "No changes to commit"
61
+ git push
62
+
63
+ - name: Create Release
64
+ id: create-release
65
+ uses: softprops/action-gh-release@v1
66
+ with:
67
+ tag_name: ${{ github.event.inputs.version }}
68
+ name: Release ${{ github.event.inputs.version }}
69
+ draft: false
70
+ prerelease: false
71
+ generate_release_notes: true
72
+ env:
73
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
74
+
75
+ build:
76
+ needs: create-release
77
+ runs-on: ubuntu-latest
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ with:
81
+ fetch-depth: 0
82
+
83
+ - name: Pull latest changes
84
+ run: git pull origin ${{ github.ref_name }}
85
+
86
+ - name: Verify version synchronization
87
+ run: |
88
+ echo "Checking version synchronization..."
89
+ PYPROJECT_VERSION=$(grep "^version = " pyproject.toml | sed 's/version = "\(.*\)"/\1/')
90
+ VERSION_PY=$(grep "__version__ = " src/masster/_version.py | sed 's/__version__ = "\(.*\)"/\1/')
91
+ INPUT_VERSION="${{ github.event.inputs.version }}"
92
+ INPUT_VERSION=${INPUT_VERSION#v}
93
+
94
+ echo "Input version: $INPUT_VERSION"
95
+ echo "pyproject.toml version: $PYPROJECT_VERSION"
96
+ echo "_version.py version: $VERSION_PY"
97
+
98
+ if [ "$PYPROJECT_VERSION" != "$INPUT_VERSION" ] || [ "$VERSION_PY" != "$INPUT_VERSION" ]; then
99
+ echo "Version mismatch detected!"
100
+ exit 1
101
+ fi
102
+ echo "All versions synchronized correctly!"
103
+
104
+ - name: Set up Python
105
+ uses: actions/setup-python@v5
106
+ with:
107
+ python-version: "3.11"
108
+
109
+ - name: Install UV
110
+ uses: astral-sh/setup-uv@v3
111
+
112
+ - name: Install dependencies
113
+ run: |
114
+ uv sync --all-extras --dev
115
+
116
+ - name: Run tests
117
+ run: |
118
+ uv run pytest tests/ -v
119
+
120
+ - name: Build package
121
+ run: |
122
+ uv build
123
+
124
+ - name: Check package
125
+ run: |
126
+ uv run twine check dist/*
127
+
128
+ - name: Upload build artifacts
129
+ uses: actions/upload-artifact@v4
130
+ with:
131
+ name: dist
132
+ path: dist/
133
+
134
+ publish-test-pypi:
135
+ needs: build
136
+ runs-on: ubuntu-latest
137
+ if: github.event.inputs.test_pypi == 'true'
138
+ environment:
139
+ name: testpypi
140
+ url: https://test.pypi.org/p/masster
141
+ permissions:
142
+ id-token: write
143
+
144
+ steps:
145
+ - name: Download build artifacts
146
+ uses: actions/download-artifact@v4
147
+ with:
148
+ name: dist
149
+ path: dist/
150
+
151
+ - name: Publish to Test PyPI
152
+ uses: pypa/gh-action-pypi-publish@release/v1
153
+ with:
154
+ repository-url: https://test.pypi.org/legacy/
155
+
156
+ publish-pypi:
157
+ needs: build
158
+ runs-on: ubuntu-latest
159
+ if: github.event.inputs.test_pypi != 'true'
160
+ environment:
161
+ name: pypi
162
+ url: https://pypi.org/p/masster
163
+ permissions:
164
+ id-token: write
165
+
166
+ steps:
167
+ - name: Download build artifacts
168
+ uses: actions/download-artifact@v4
169
+ with:
170
+ name: dist
171
+ path: dist/
172
+
173
+ - name: Publish to PyPI
174
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,88 @@
1
+ name: Security Scan
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ scan_type:
7
+ description: 'Type of security scan to run'
8
+ required: false
9
+ default: 'all'
10
+ type: choice
11
+ options:
12
+ - all
13
+ - safety-only
14
+ - bandit-only
15
+ upload_reports:
16
+ description: 'Upload security reports as artifacts'
17
+ required: false
18
+ default: true
19
+ type: boolean
20
+ schedule:
21
+ - cron: '0 3 * * 1' # Weekly on Monday at 3 AM UTC
22
+
23
+ jobs:
24
+ security:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: "3.11"
33
+
34
+ - name: Install UV
35
+ uses: astral-sh/setup-uv@v3
36
+
37
+ - name: Install dependencies
38
+ run: |
39
+ uv sync --all-extras --dev
40
+
41
+ - name: Run safety check
42
+ if: github.event_name == 'schedule' || github.event.inputs.scan_type == 'all' || github.event.inputs.scan_type == 'safety-only'
43
+ run: |
44
+ echo "Running Safety security scan..."
45
+ uv run safety check --json --output safety-report.json || true
46
+ echo "Safety scan completed. Check safety-report.json for results."
47
+
48
+ - name: Run bandit security check
49
+ if: github.event_name == 'schedule' || github.event.inputs.scan_type == 'all' || github.event.inputs.scan_type == 'bandit-only'
50
+ run: |
51
+ echo "Running Bandit security scan..."
52
+ uv run bandit -r src/masster -f json -o bandit-report.json || true
53
+ echo "Bandit scan completed. Check bandit-report.json for results."
54
+
55
+ - name: Display scan summary
56
+ run: |
57
+ echo "=== Security Scan Summary ==="
58
+ if [ "${{ github.event_name }}" = "schedule" ]; then
59
+ echo "Scan type: all (scheduled run)"
60
+ else
61
+ echo "Scan type: ${{ github.event.inputs.scan_type || 'all' }}"
62
+ fi
63
+
64
+ if [[ ("${{ github.event_name }}" == "schedule") || ("${{ github.event.inputs.scan_type }}" == "all" || "${{ github.event.inputs.scan_type }}" == "safety-only") ]] && [ -f safety-report.json ]; then
65
+ echo "Safety report generated: safety-report.json"
66
+ # Show summary if available
67
+ if command -v jq &> /dev/null && [ -s safety-report.json ]; then
68
+ echo "Safety vulnerabilities found: $(jq '.vulnerabilities | length' safety-report.json 2>/dev/null || echo 'Unable to parse')"
69
+ fi
70
+ fi
71
+
72
+ if [[ ("${{ github.event_name }}" == "schedule") || ("${{ github.event.inputs.scan_type }}" == "all" || "${{ github.event.inputs.scan_type }}" == "bandit-only") ]] && [ -f bandit-report.json ]; then
73
+ echo "Bandit report generated: bandit-report.json"
74
+ # Show summary if available
75
+ if command -v jq &> /dev/null && [ -s bandit-report.json ]; then
76
+ echo "Bandit issues found: $(jq '.results | length' bandit-report.json 2>/dev/null || echo 'Unable to parse')"
77
+ fi
78
+ fi
79
+
80
+ - name: Upload security reports
81
+ if: github.event_name == 'schedule' || github.event.inputs.upload_reports == 'true'
82
+ uses: actions/upload-artifact@v4
83
+ with:
84
+ name: security-reports-${{ github.run_number }}
85
+ path: |
86
+ safety-report.json
87
+ bandit-report.json
88
+ retention-days: 30
@@ -0,0 +1,164 @@
1
+ name: Test Suite
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ run_all_tests:
7
+ description: 'Run tests on all OS and Python versions'
8
+ required: false
9
+ default: true
10
+ type: boolean
11
+ target_os:
12
+ description: 'Target OS for testing (if not running all)'
13
+ required: false
14
+ default: 'ubuntu-latest'
15
+ type: choice
16
+ options:
17
+ - ubuntu-latest
18
+ - windows-latest
19
+ - macos-latest
20
+ python_version:
21
+ description: 'Python version for testing (if not running all)'
22
+ required: false
23
+ default: '3.11'
24
+ type: choice
25
+ options:
26
+ - '3.11'
27
+ - '3.12'
28
+ - '3.13'
29
+ schedule:
30
+ - cron: '0 2 * * 1' # Weekly on Monday at 2 AM UTC
31
+
32
+ jobs:
33
+ test-all:
34
+ if: github.event_name == 'schedule' || github.event.inputs.run_all_tests == 'true'
35
+ runs-on: ${{ matrix.os }}
36
+ strategy:
37
+ fail-fast: false
38
+ matrix:
39
+ os: [ubuntu-latest, windows-latest, macos-latest]
40
+ python-version: ["3.11", "3.12", "3.13"]
41
+ exclude:
42
+ # Exclude macOS with Python 3.11 and 3.12 to reduce CI costs
43
+ - os: macos-latest
44
+ python-version: "3.11"
45
+ - os: macos-latest
46
+ python-version: "3.12"
47
+ # Exclude Windows with Python 3.12 to reduce CI costs
48
+ - os: windows-latest
49
+ python-version: "3.12"
50
+
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+
54
+ - name: Set up Python ${{ matrix.python-version }}
55
+ uses: actions/setup-python@v5
56
+ with:
57
+ python-version: ${{ matrix.python-version }}
58
+
59
+ - name: Install UV
60
+ uses: astral-sh/setup-uv@v3
61
+ with:
62
+ enable-cache: true
63
+ cache-dependency-glob: "uv.lock"
64
+
65
+ - name: Install dependencies
66
+ run: |
67
+ uv sync --all-extras --dev
68
+
69
+ - name: Lint with flake8
70
+ run: |
71
+ uv run flake8 src/masster tests --count --select=E9,F63,F7,F82 --show-source --statistics
72
+ uv run flake8 src/masster tests --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics
73
+
74
+ - name: Type check with mypy
75
+ run: |
76
+ uv run mypy src/masster --ignore-missing-imports --no-strict-optional
77
+
78
+ - name: Test with pytest
79
+ run: |
80
+ uv run pytest tests/ -v --cov=masster --cov-report=xml --cov-report=term-missing
81
+
82
+ - name: Upload coverage to Codecov
83
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
84
+ uses: codecov/codecov-action@v3
85
+ with:
86
+ file: ./coverage.xml
87
+ flags: unittests
88
+ name: codecov-umbrella
89
+
90
+ test-selective:
91
+ if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_all_tests != 'true'
92
+ runs-on: ${{ github.event.inputs.target_os || 'ubuntu-latest' }}
93
+
94
+ steps:
95
+ - uses: actions/checkout@v4
96
+
97
+ - name: Set up Python ${{ github.event.inputs.python_version || '3.11' }}
98
+ uses: actions/setup-python@v5
99
+ with:
100
+ python-version: ${{ github.event.inputs.python_version || '3.11' }}
101
+
102
+ - name: Install UV
103
+ uses: astral-sh/setup-uv@v3
104
+ with:
105
+ enable-cache: true
106
+ cache-dependency-glob: "uv.lock"
107
+
108
+ - name: Install dependencies
109
+ run: |
110
+ uv sync --all-extras --dev
111
+
112
+ - name: Lint with flake8
113
+ run: |
114
+ uv run flake8 src/masster tests --count --select=E9,F63,F7,F82 --show-source --statistics
115
+ uv run flake8 src/masster tests --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics
116
+
117
+ - name: Type check with mypy
118
+ run: |
119
+ uv run mypy src/masster --ignore-missing-imports --no-strict-optional
120
+
121
+ - name: Test with pytest
122
+ run: |
123
+ uv run pytest tests/ -v --cov=masster --cov-report=xml --cov-report=term-missing
124
+
125
+ - name: Upload coverage to Codecov
126
+ if: github.event.inputs.target_os == 'ubuntu-latest' && github.event.inputs.python_version == '3.11'
127
+ uses: codecov/codecov-action@v3
128
+ with:
129
+ file: ./coverage.xml
130
+ flags: unittests
131
+ name: codecov-umbrella
132
+
133
+ build:
134
+ needs: [test-all, test-selective]
135
+ if: always() && (needs.test-all.result == 'success' || needs.test-selective.result == 'success')
136
+ runs-on: ubuntu-latest
137
+ steps:
138
+ - uses: actions/checkout@v4
139
+
140
+ - name: Set up Python
141
+ uses: actions/setup-python@v5
142
+ with:
143
+ python-version: "3.11"
144
+
145
+ - name: Install UV
146
+ uses: astral-sh/setup-uv@v3
147
+
148
+ - name: Install dependencies
149
+ run: |
150
+ uv sync --all-extras --dev
151
+
152
+ - name: Build package
153
+ run: |
154
+ uv build
155
+
156
+ - name: Check package
157
+ run: |
158
+ uv run twine check dist/*
159
+
160
+ - name: Upload build artifacts
161
+ uses: actions/upload-artifact@v4
162
+ with:
163
+ name: dist
164
+ path: dist/