galley-jl-python 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.
- galley_jl_python-0.1.0/LICENSE +21 -0
- galley_jl_python-0.1.0/PKG-INFO +214 -0
- galley_jl_python-0.1.0/README.md +182 -0
- galley_jl_python-0.1.0/pyproject.toml +146 -0
- galley_jl_python-0.1.0/src/galley_jl_python/__init__.py +361 -0
- galley_jl_python-0.1.0/src/galley_jl_python/_array_api_info.py +94 -0
- galley_jl_python-0.1.0/src/galley_jl_python/_sysimage.py +222 -0
- galley_jl_python-0.1.0/src/galley_jl_python/compiled.py +171 -0
- galley_jl_python-0.1.0/src/galley_jl_python/dtypes.py +61 -0
- galley_jl_python-0.1.0/src/galley_jl_python/einstein.py +561 -0
- galley_jl_python-0.1.0/src/galley_jl_python/errors.py +2 -0
- galley_jl_python-0.1.0/src/galley_jl_python/finch_fused.py +33 -0
- galley_jl_python-0.1.0/src/galley_jl_python/io.py +15 -0
- galley_jl_python-0.1.0/src/galley_jl_python/julia.py +37 -0
- galley_jl_python-0.1.0/src/galley_jl_python/juliapkg.json +386 -0
- galley_jl_python-0.1.0/src/galley_jl_python/juliapkg_dev.json +22 -0
- galley_jl_python-0.1.0/src/galley_jl_python/levels.py +110 -0
- galley_jl_python-0.1.0/src/galley_jl_python/linalg/__init__.py +3 -0
- galley_jl_python-0.1.0/src/galley_jl_python/linalg/_linalg.py +26 -0
- galley_jl_python-0.1.0/src/galley_jl_python/tensor.py +1739 -0
- galley_jl_python-0.1.0/src/galley_jl_python/typing.py +17 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Willow Ahrens
|
|
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.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: galley-jl-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sparse Tensor Programming in Python powered by Finch.jl
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: Willow Ahrens
|
|
7
|
+
Author-email: willow.marie.ahrens@gmail.com
|
|
8
|
+
Requires-Python: >=3.11,<4.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
Requires-Dist: finch-tensor (>=0.7.0,<0.8.0)
|
|
17
|
+
Requires-Dist: hypothesis (>=6.151.9,<7.0.0) ; extra == "test"
|
|
18
|
+
Requires-Dist: juliacall (>=0.9.36,<0.9.37)
|
|
19
|
+
Requires-Dist: juliapkg (>=0.1.16,<0.2.0)
|
|
20
|
+
Requires-Dist: lark (>=1.3.0,<2.0.0)
|
|
21
|
+
Requires-Dist: ndindex (>=1.10.1,<2.0.0) ; extra == "test"
|
|
22
|
+
Requires-Dist: numba (>=0.61,<0.63.1)
|
|
23
|
+
Requires-Dist: numpy (>=1.19,<2.4)
|
|
24
|
+
Requires-Dist: pytest (>=7.4.4,<7.6) ; extra == "test"
|
|
25
|
+
Requires-Dist: pytest-cov (>=4.1.0,<4.2) ; extra == "test"
|
|
26
|
+
Requires-Dist: pytest-json-report (>=1.5.0,<2.0.0) ; extra == "test"
|
|
27
|
+
Requires-Dist: pytest-xdist (>=3.6.1,<4) ; extra == "test"
|
|
28
|
+
Requires-Dist: scipy (>=1.7,<1.17) ; extra == "test"
|
|
29
|
+
Requires-Dist: sparse (>=0.17.0,<0.17.1) ; extra == "test"
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# galley-jl-python
|
|
33
|
+
A sparse tensor library for Python, backed by the
|
|
34
|
+
[Galley.jl](https://github.com/finch-tensor/Galley.jl) framework.
|
|
35
|
+
|
|
36
|
+
## Source
|
|
37
|
+
|
|
38
|
+
The source code for `galley-jl-python` is available on GitHub at [https://github.com/finch-tensor/galley-jl-python](https://github.com/finch-tensor/galley-jl-python).
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
`galley-jl-python` is available on PyPI, and can be installed with pip:
|
|
43
|
+
```bash
|
|
44
|
+
pip install galley-jl-python
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Galley needs a Python linked against **OpenSSL 3.5 or newer**. It runs Julia
|
|
48
|
+
1.12, which bundles OpenSSL 3.5 in the same process as Python. Pythons from
|
|
49
|
+
conda-forge, including through pixi or conda, meet this. Many system and
|
|
50
|
+
pyenv-built Pythons still use OpenSSL 3.0, and there `import galley_jl_python`
|
|
51
|
+
fails with an error that says so. Check with
|
|
52
|
+
`python -c "import ssl; print(ssl.OPENSSL_VERSION)"`.
|
|
53
|
+
|
|
54
|
+
## Contributing
|
|
55
|
+
|
|
56
|
+
### Development environment
|
|
57
|
+
|
|
58
|
+
Galley uses [pixi](https://pixi.sh) for development. All configuration lives in
|
|
59
|
+
`pyproject.toml`: the package metadata and dependencies are under `[project]`,
|
|
60
|
+
and pixi's settings are under `[tool.pixi]`.
|
|
61
|
+
|
|
62
|
+
To set up, clone the repository and run:
|
|
63
|
+
```bash
|
|
64
|
+
pixi install # the default environment
|
|
65
|
+
pixi install -e test # adds the test dependencies (the `test` extra)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
pixi installs the package in editable mode. Julia is not a pixi dependency:
|
|
69
|
+
[juliapkg](https://github.com/JuliaPy/pyjuliapkg) installs the pinned Julia
|
|
70
|
+
version and packages the first time `galley_jl_python` is imported. To trigger
|
|
71
|
+
that, and to fetch the sysimage (see below), run:
|
|
72
|
+
```bash
|
|
73
|
+
pixi run compile
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Run any other command inside an environment with `pixi run`, for example
|
|
77
|
+
`pixi run -e test python`.
|
|
78
|
+
|
|
79
|
+
The package is still built and published with Poetry (see
|
|
80
|
+
[Publishing](#publishing)).
|
|
81
|
+
|
|
82
|
+
### Working with a local copy of Finch.jl
|
|
83
|
+
The `develop.py` script can be used to set up a local copy of Finch.jl for
|
|
84
|
+
development. Run it with `pixi run python develop.py`.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Usage:
|
|
88
|
+
develop.py [--restore] [--path <path>]
|
|
89
|
+
|
|
90
|
+
Options:
|
|
91
|
+
--restore Restore the original juliapkg.json file.
|
|
92
|
+
--path Path to the local copy of Finch.jl [default: ../Finch.jl].
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Julia sysimage
|
|
96
|
+
|
|
97
|
+
Most of Galley's startup time is Julia compiling Finch itself. A prebuilt Julia
|
|
98
|
+
sysimage removes it: the first matmul of a session drops from about 4.5 minutes
|
|
99
|
+
to a few seconds.
|
|
100
|
+
|
|
101
|
+
- `import galley_jl_python` uses the image for the current platform and Julia
|
|
102
|
+
environment. If it isn't cached in `~/.cache/galley-jl-python/`
|
|
103
|
+
(`GALLEY_JL_PYTHON_CACHE` overrides this), the import downloads it from the
|
|
104
|
+
project's GitHub releases first, about 900 MB once per environment. It then
|
|
105
|
+
checks that the image loads, and if there's no image or anything fails, Julia
|
|
106
|
+
starts without it. Set `GALLEY_JL_PYTHON_SYSIMAGE=0` to turn all of this off.
|
|
107
|
+
- `pixi run fetch-sysimage` downloads the image ahead of time. `pixi run compile`
|
|
108
|
+
and `pixi run test` run this step first.
|
|
109
|
+
- `pixi run build-sysimage` builds the image locally instead, in about half an
|
|
110
|
+
hour.
|
|
111
|
+
|
|
112
|
+
An image works only with the exact Julia and package versions it was built
|
|
113
|
+
from. For this reason `src/galley_jl_python/juliapkg.json` pins Julia and every
|
|
114
|
+
Julia package. Each image's name includes a hash of that environment. A local
|
|
115
|
+
Finch.jl from `develop.py` therefore runs without the image.
|
|
116
|
+
|
|
117
|
+
To update the Julia dependencies:
|
|
118
|
+
|
|
119
|
+
1. Loosen the pins you want to change.
|
|
120
|
+
2. Resolve with `pixi run compile`.
|
|
121
|
+
3. Re-pin with `python scripts/sysimage/pin_julia_deps.py`.
|
|
122
|
+
|
|
123
|
+
Pushing the new pins to `main` runs the "Sysimage" GitHub Action. It builds
|
|
124
|
+
images for Linux, macOS and Windows and publishes them to a `sysimage-<hash>`
|
|
125
|
+
GitHub release, where imports and `fetch-sysimage` find them. The action can also be run
|
|
126
|
+
manually from the Actions tab.
|
|
127
|
+
|
|
128
|
+
### Publishing
|
|
129
|
+
|
|
130
|
+
The "Publish" GitHub Action is a manual workflow for publishing Python packages to PyPI using Poetry. It handles the version management based on the `pyproject.toml` file and automates tagging and creating GitHub releases.
|
|
131
|
+
|
|
132
|
+
#### Version Update
|
|
133
|
+
|
|
134
|
+
Before initiating the "Publish" action, update the package's version number in `pyproject.toml`. Follow semantic versioning guidelines for this update.
|
|
135
|
+
|
|
136
|
+
#### Triggering the Action
|
|
137
|
+
|
|
138
|
+
The action is triggered manually. Once the version in `pyproject.toml` is updated, manually start the "Publish" action from the GitHub repository's Actions tab.
|
|
139
|
+
|
|
140
|
+
#### Process and Outcomes
|
|
141
|
+
|
|
142
|
+
On successful execution, the action publishes the package to PyPI and tags the release in the GitHub repository. If the version number is not updated, the action fails to publish to PyPI, and no tagging or release is done. In case of failure, correct the version number and rerun the action.
|
|
143
|
+
|
|
144
|
+
#### Best Practices
|
|
145
|
+
|
|
146
|
+
- Ensure the version number in `pyproject.toml` is updated before triggering the action.
|
|
147
|
+
- Regularly check action logs for successful completion or to identify issues.
|
|
148
|
+
|
|
149
|
+
### Pre-commit hooks
|
|
150
|
+
|
|
151
|
+
The hooks run in their own `pre-commit` environment, which doesn't install
|
|
152
|
+
galley's dependencies or Julia.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
pixi run pre-commit-install # run the hooks on every `git commit`
|
|
156
|
+
pixi run pre-commit # run every hook on every file now
|
|
157
|
+
pixi run pre-commit ruff # the same, skipping the listed hook ids
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
To run a single hook, use `pixi shell -e pre-commit` and then
|
|
161
|
+
`pre-commit run <hook-id> -a`.
|
|
162
|
+
|
|
163
|
+
### Testing
|
|
164
|
+
|
|
165
|
+
Galley uses [pytest](https://docs.pytest.org/en/latest/) for testing. To run the
|
|
166
|
+
tests:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
pixi run test # one pytest-xdist worker per CPU
|
|
170
|
+
pixi run test 4 # or a fixed number of workers
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This runs `compile` first, then two suites one after the other, each spread
|
|
174
|
+
over the workers:
|
|
175
|
+
|
|
176
|
+
- `pixi run test-unit` runs the unit tests.
|
|
177
|
+
- `pixi run test-array-api` runs the Array API tests described below.
|
|
178
|
+
|
|
179
|
+
Each worker is a separate Julia process that uses 1–2 GB of memory, so lower
|
|
180
|
+
the worker count on machines with little memory.
|
|
181
|
+
|
|
182
|
+
To run a subset, call pytest in the test environment directly:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
pixi run -e test pytest tests/test_fused.py
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Array API tests are included in `tests/test_array_api.py`. These tests invoke
|
|
189
|
+
the [Array API Conformance Tests](https://github.com/data-apis/array-api-tests).
|
|
190
|
+
To forward `pytest` options to the nested
|
|
191
|
+
`array-api-tests` invocation, use `--array-api` (alias:
|
|
192
|
+
`--array-api-pytest-args`):
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
pixi run -e test pytest tests/test_array_api.py \
|
|
196
|
+
--array-api="-k creation_functions" \
|
|
197
|
+
--array-api="-x"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
By default, the nested Array API run forwards common top-level pytest options
|
|
201
|
+
from your main invocation:
|
|
202
|
+
|
|
203
|
+
- `-x`/`--maxfail`
|
|
204
|
+
- `-s`
|
|
205
|
+
- `-v`, `-vv`, etc.
|
|
206
|
+
- `-k`
|
|
207
|
+
|
|
208
|
+
You can repeat `--array-api` (or `--array-api-pytest-args`) multiple times.
|
|
209
|
+
Each value is parsed like shell arguments and appended to the nested `pytest`
|
|
210
|
+
call.
|
|
211
|
+
|
|
212
|
+
`ARRAY_API_TESTS_ARGS` is still supported as a fallback for compatibility, but
|
|
213
|
+
the CLI option is preferred.
|
|
214
|
+
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# galley-jl-python
|
|
2
|
+
A sparse tensor library for Python, backed by the
|
|
3
|
+
[Galley.jl](https://github.com/finch-tensor/Galley.jl) framework.
|
|
4
|
+
|
|
5
|
+
## Source
|
|
6
|
+
|
|
7
|
+
The source code for `galley-jl-python` is available on GitHub at [https://github.com/finch-tensor/galley-jl-python](https://github.com/finch-tensor/galley-jl-python).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
`galley-jl-python` is available on PyPI, and can be installed with pip:
|
|
12
|
+
```bash
|
|
13
|
+
pip install galley-jl-python
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Galley needs a Python linked against **OpenSSL 3.5 or newer**. It runs Julia
|
|
17
|
+
1.12, which bundles OpenSSL 3.5 in the same process as Python. Pythons from
|
|
18
|
+
conda-forge, including through pixi or conda, meet this. Many system and
|
|
19
|
+
pyenv-built Pythons still use OpenSSL 3.0, and there `import galley_jl_python`
|
|
20
|
+
fails with an error that says so. Check with
|
|
21
|
+
`python -c "import ssl; print(ssl.OPENSSL_VERSION)"`.
|
|
22
|
+
|
|
23
|
+
## Contributing
|
|
24
|
+
|
|
25
|
+
### Development environment
|
|
26
|
+
|
|
27
|
+
Galley uses [pixi](https://pixi.sh) for development. All configuration lives in
|
|
28
|
+
`pyproject.toml`: the package metadata and dependencies are under `[project]`,
|
|
29
|
+
and pixi's settings are under `[tool.pixi]`.
|
|
30
|
+
|
|
31
|
+
To set up, clone the repository and run:
|
|
32
|
+
```bash
|
|
33
|
+
pixi install # the default environment
|
|
34
|
+
pixi install -e test # adds the test dependencies (the `test` extra)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
pixi installs the package in editable mode. Julia is not a pixi dependency:
|
|
38
|
+
[juliapkg](https://github.com/JuliaPy/pyjuliapkg) installs the pinned Julia
|
|
39
|
+
version and packages the first time `galley_jl_python` is imported. To trigger
|
|
40
|
+
that, and to fetch the sysimage (see below), run:
|
|
41
|
+
```bash
|
|
42
|
+
pixi run compile
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Run any other command inside an environment with `pixi run`, for example
|
|
46
|
+
`pixi run -e test python`.
|
|
47
|
+
|
|
48
|
+
The package is still built and published with Poetry (see
|
|
49
|
+
[Publishing](#publishing)).
|
|
50
|
+
|
|
51
|
+
### Working with a local copy of Finch.jl
|
|
52
|
+
The `develop.py` script can be used to set up a local copy of Finch.jl for
|
|
53
|
+
development. Run it with `pixi run python develop.py`.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Usage:
|
|
57
|
+
develop.py [--restore] [--path <path>]
|
|
58
|
+
|
|
59
|
+
Options:
|
|
60
|
+
--restore Restore the original juliapkg.json file.
|
|
61
|
+
--path Path to the local copy of Finch.jl [default: ../Finch.jl].
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Julia sysimage
|
|
65
|
+
|
|
66
|
+
Most of Galley's startup time is Julia compiling Finch itself. A prebuilt Julia
|
|
67
|
+
sysimage removes it: the first matmul of a session drops from about 4.5 minutes
|
|
68
|
+
to a few seconds.
|
|
69
|
+
|
|
70
|
+
- `import galley_jl_python` uses the image for the current platform and Julia
|
|
71
|
+
environment. If it isn't cached in `~/.cache/galley-jl-python/`
|
|
72
|
+
(`GALLEY_JL_PYTHON_CACHE` overrides this), the import downloads it from the
|
|
73
|
+
project's GitHub releases first, about 900 MB once per environment. It then
|
|
74
|
+
checks that the image loads, and if there's no image or anything fails, Julia
|
|
75
|
+
starts without it. Set `GALLEY_JL_PYTHON_SYSIMAGE=0` to turn all of this off.
|
|
76
|
+
- `pixi run fetch-sysimage` downloads the image ahead of time. `pixi run compile`
|
|
77
|
+
and `pixi run test` run this step first.
|
|
78
|
+
- `pixi run build-sysimage` builds the image locally instead, in about half an
|
|
79
|
+
hour.
|
|
80
|
+
|
|
81
|
+
An image works only with the exact Julia and package versions it was built
|
|
82
|
+
from. For this reason `src/galley_jl_python/juliapkg.json` pins Julia and every
|
|
83
|
+
Julia package. Each image's name includes a hash of that environment. A local
|
|
84
|
+
Finch.jl from `develop.py` therefore runs without the image.
|
|
85
|
+
|
|
86
|
+
To update the Julia dependencies:
|
|
87
|
+
|
|
88
|
+
1. Loosen the pins you want to change.
|
|
89
|
+
2. Resolve with `pixi run compile`.
|
|
90
|
+
3. Re-pin with `python scripts/sysimage/pin_julia_deps.py`.
|
|
91
|
+
|
|
92
|
+
Pushing the new pins to `main` runs the "Sysimage" GitHub Action. It builds
|
|
93
|
+
images for Linux, macOS and Windows and publishes them to a `sysimage-<hash>`
|
|
94
|
+
GitHub release, where imports and `fetch-sysimage` find them. The action can also be run
|
|
95
|
+
manually from the Actions tab.
|
|
96
|
+
|
|
97
|
+
### Publishing
|
|
98
|
+
|
|
99
|
+
The "Publish" GitHub Action is a manual workflow for publishing Python packages to PyPI using Poetry. It handles the version management based on the `pyproject.toml` file and automates tagging and creating GitHub releases.
|
|
100
|
+
|
|
101
|
+
#### Version Update
|
|
102
|
+
|
|
103
|
+
Before initiating the "Publish" action, update the package's version number in `pyproject.toml`. Follow semantic versioning guidelines for this update.
|
|
104
|
+
|
|
105
|
+
#### Triggering the Action
|
|
106
|
+
|
|
107
|
+
The action is triggered manually. Once the version in `pyproject.toml` is updated, manually start the "Publish" action from the GitHub repository's Actions tab.
|
|
108
|
+
|
|
109
|
+
#### Process and Outcomes
|
|
110
|
+
|
|
111
|
+
On successful execution, the action publishes the package to PyPI and tags the release in the GitHub repository. If the version number is not updated, the action fails to publish to PyPI, and no tagging or release is done. In case of failure, correct the version number and rerun the action.
|
|
112
|
+
|
|
113
|
+
#### Best Practices
|
|
114
|
+
|
|
115
|
+
- Ensure the version number in `pyproject.toml` is updated before triggering the action.
|
|
116
|
+
- Regularly check action logs for successful completion or to identify issues.
|
|
117
|
+
|
|
118
|
+
### Pre-commit hooks
|
|
119
|
+
|
|
120
|
+
The hooks run in their own `pre-commit` environment, which doesn't install
|
|
121
|
+
galley's dependencies or Julia.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pixi run pre-commit-install # run the hooks on every `git commit`
|
|
125
|
+
pixi run pre-commit # run every hook on every file now
|
|
126
|
+
pixi run pre-commit ruff # the same, skipping the listed hook ids
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
To run a single hook, use `pixi shell -e pre-commit` and then
|
|
130
|
+
`pre-commit run <hook-id> -a`.
|
|
131
|
+
|
|
132
|
+
### Testing
|
|
133
|
+
|
|
134
|
+
Galley uses [pytest](https://docs.pytest.org/en/latest/) for testing. To run the
|
|
135
|
+
tests:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pixi run test # one pytest-xdist worker per CPU
|
|
139
|
+
pixi run test 4 # or a fixed number of workers
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This runs `compile` first, then two suites one after the other, each spread
|
|
143
|
+
over the workers:
|
|
144
|
+
|
|
145
|
+
- `pixi run test-unit` runs the unit tests.
|
|
146
|
+
- `pixi run test-array-api` runs the Array API tests described below.
|
|
147
|
+
|
|
148
|
+
Each worker is a separate Julia process that uses 1–2 GB of memory, so lower
|
|
149
|
+
the worker count on machines with little memory.
|
|
150
|
+
|
|
151
|
+
To run a subset, call pytest in the test environment directly:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pixi run -e test pytest tests/test_fused.py
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Array API tests are included in `tests/test_array_api.py`. These tests invoke
|
|
158
|
+
the [Array API Conformance Tests](https://github.com/data-apis/array-api-tests).
|
|
159
|
+
To forward `pytest` options to the nested
|
|
160
|
+
`array-api-tests` invocation, use `--array-api` (alias:
|
|
161
|
+
`--array-api-pytest-args`):
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
pixi run -e test pytest tests/test_array_api.py \
|
|
165
|
+
--array-api="-k creation_functions" \
|
|
166
|
+
--array-api="-x"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
By default, the nested Array API run forwards common top-level pytest options
|
|
170
|
+
from your main invocation:
|
|
171
|
+
|
|
172
|
+
- `-x`/`--maxfail`
|
|
173
|
+
- `-s`
|
|
174
|
+
- `-v`, `-vv`, etc.
|
|
175
|
+
- `-k`
|
|
176
|
+
|
|
177
|
+
You can repeat `--array-api` (or `--array-api-pytest-args`) multiple times.
|
|
178
|
+
Each value is parsed like shell arguments and appended to the nested `pytest`
|
|
179
|
+
call.
|
|
180
|
+
|
|
181
|
+
`ARRAY_API_TESTS_ARGS` is still supported as a fallback for compatibility, but
|
|
182
|
+
the CLI option is preferred.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "galley-jl-python"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Sparse Tensor Programming in Python powered by Finch.jl"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{name = "Willow Ahrens", email = "willow.marie.ahrens@gmail.com"}]
|
|
7
|
+
requires-python = ">=3.11,<4.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"juliapkg (>=0.1.16,<0.2.0)",
|
|
10
|
+
"numpy (>=1.19,<2.4)",
|
|
11
|
+
"numba>=0.61,<0.63.1",
|
|
12
|
+
# juliacall pins PythonCall to its own version. juliapkg.json's pins and the
|
|
13
|
+
# prebuilt sysimage (see scripts/sysimage/relocate_pythoncall.jl) are built
|
|
14
|
+
# against PythonCall 0.9.36, and 0.9.37 needs a newer CondaPkg than is pinned.
|
|
15
|
+
# To move: loosen this and the CondaPkg pin, then follow pin_julia_deps.py.
|
|
16
|
+
"juliacall (>=0.9.36,<0.9.37)",
|
|
17
|
+
"lark (>=1.3.0,<2.0.0)",
|
|
18
|
+
"finch-tensor>=0.7.0,<0.8.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.poetry]
|
|
22
|
+
packages = [{include = "galley_jl_python", from = "src"}]
|
|
23
|
+
requires-poetry = ">=2.0,<3.0"
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
test = [
|
|
27
|
+
"pytest>=7.4.4,<7.6",
|
|
28
|
+
"pytest-cov>=4.1.0,<4.2",
|
|
29
|
+
"sparse>=0.17.0,<0.17.1",
|
|
30
|
+
"scipy>=1.7,<1.17",
|
|
31
|
+
"hypothesis (>=6.151.9,<7.0.0)",
|
|
32
|
+
"ndindex (>=1.10.1,<2.0.0)",
|
|
33
|
+
"pytest-json-report (>=1.5.0,<2.0.0)",
|
|
34
|
+
"pytest-xdist>=3.6.1,<4",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["poetry-core>=1.0.8"]
|
|
39
|
+
build-backend = "poetry.core.masonry.api"
|
|
40
|
+
|
|
41
|
+
[tool.pixi.workspace]
|
|
42
|
+
channels = ["conda-forge"]
|
|
43
|
+
platforms = [
|
|
44
|
+
{ name = "linux-amd64", platform = "linux-64", glibc = "2.34" },
|
|
45
|
+
{ name = "linux-arm64", platform = "linux-aarch64", glibc = "2.34" },
|
|
46
|
+
{ name = "macos-arm64", platform = "osx-arm64", macos = "15.0" },
|
|
47
|
+
{ name = "win-amd64", platform = "win-64" },
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[tool.pixi.dependencies]
|
|
51
|
+
python = ">=3.11,<3.14"
|
|
52
|
+
|
|
53
|
+
[tool.pixi.pypi-dependencies]
|
|
54
|
+
galley-jl-python = { path = ".", editable = true }
|
|
55
|
+
|
|
56
|
+
[tool.pixi.tasks]
|
|
57
|
+
# pixi has no post-install hook, so the entry-point tasks fetch the sysimage
|
|
58
|
+
compile = { cmd = "python -c 'import galley_jl_python'", depends-on = ["fetch-sysimage"] }
|
|
59
|
+
build-sysimage = "python scripts/sysimage/build.py"
|
|
60
|
+
fetch-sysimage = "python scripts/sysimage/fetch.py"
|
|
61
|
+
|
|
62
|
+
# `pixi run test [njobs]` runs both suites, one after the other, each spread
|
|
63
|
+
# over `njobs` pytest-xdist workers (default: one per CPU).
|
|
64
|
+
[tool.pixi.feature.test.tasks.test]
|
|
65
|
+
args = [{ arg = "njobs", default = "auto" }]
|
|
66
|
+
# a no-op cmd, since `default-environment` is only allowed on tasks with one
|
|
67
|
+
cmd = "echo all test suites passed"
|
|
68
|
+
default-environment = "test"
|
|
69
|
+
depends-on = [
|
|
70
|
+
{ task = "test-unit", args = ["{{ njobs }}"] },
|
|
71
|
+
{ task = "test-array-api", args = ["{{ njobs }}"] },
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[tool.pixi.feature.test.tasks.test-unit]
|
|
75
|
+
args = [{ arg = "njobs", default = "auto" }]
|
|
76
|
+
default-environment = "test"
|
|
77
|
+
cmd = "pytest -n {{ njobs }} --ignore=tests/test_array_api.py"
|
|
78
|
+
depends-on = ["compile"]
|
|
79
|
+
|
|
80
|
+
# The Array API wrapper is a single test that runs array-api-tests in a nested
|
|
81
|
+
# pytest, so the workers go to the nested run. It skips coverage and writes its
|
|
82
|
+
# own junit file so it doesn't overwrite test-unit's reports.
|
|
83
|
+
[tool.pixi.feature.test.tasks.test-array-api]
|
|
84
|
+
args = [{ arg = "njobs", default = "auto" }]
|
|
85
|
+
default-environment = "test"
|
|
86
|
+
cmd = "pytest tests/test_array_api.py --no-cov --junitxml=junit/array-api-results.xml --array-api='-n {{ njobs }}'"
|
|
87
|
+
depends-on = ["compile"]
|
|
88
|
+
|
|
89
|
+
# Hooks run in their own environment, without galley's dependencies or Julia.
|
|
90
|
+
[tool.pixi.feature.pre-commit.dependencies]
|
|
91
|
+
pre-commit = "*"
|
|
92
|
+
|
|
93
|
+
[tool.pixi.feature.pre-commit.tasks]
|
|
94
|
+
pre-commit-install = "pre-commit install"
|
|
95
|
+
|
|
96
|
+
# `pixi run pre-commit [skip]` runs every hook on every file; `skip` is a
|
|
97
|
+
# comma-separated list of hook ids to leave out.
|
|
98
|
+
[tool.pixi.feature.pre-commit.tasks.pre-commit]
|
|
99
|
+
args = [{ arg = "skip", default = "" }]
|
|
100
|
+
env = { SKIP = "{{ skip }}" }
|
|
101
|
+
cmd = "pre-commit run -a"
|
|
102
|
+
|
|
103
|
+
[tool.pixi.feature.py311.dependencies]
|
|
104
|
+
python = "3.11.*"
|
|
105
|
+
|
|
106
|
+
[tool.pixi.feature.py312.dependencies]
|
|
107
|
+
python = "3.12.*"
|
|
108
|
+
|
|
109
|
+
[tool.pixi.feature.py313.dependencies]
|
|
110
|
+
python = "3.13.*"
|
|
111
|
+
|
|
112
|
+
[tool.pixi.environments]
|
|
113
|
+
test = { features = ["test"], solve-group = "default" }
|
|
114
|
+
test-py311 = ["test", "py311"]
|
|
115
|
+
test-py312 = ["test", "py312"]
|
|
116
|
+
test-py313 = ["test", "py313"]
|
|
117
|
+
pre-commit = { features = ["pre-commit"], no-default-feature = true }
|
|
118
|
+
|
|
119
|
+
[tool.ruff]
|
|
120
|
+
line-length = 88
|
|
121
|
+
|
|
122
|
+
[tool.ruff.lint]
|
|
123
|
+
select = ["F", "E", "W", "I", "B", "UP", "YTT", "BLE", "C4", "T10", "ISC", "ICN", "PIE", "PYI", "RSE", "RET", "SIM", "PGH", "FLY", "NPY", "PERF", "RUF022"]
|
|
124
|
+
ignore = ["PYI024"]
|
|
125
|
+
|
|
126
|
+
[tool.ruff.lint.isort.sections]
|
|
127
|
+
numpy = ["numpy", "numpy.*", "scipy", "scipy.*"]
|
|
128
|
+
pytest = ["pytest", "pytest.*"]
|
|
129
|
+
|
|
130
|
+
[tool.ruff.format]
|
|
131
|
+
quote-style = "double"
|
|
132
|
+
docstring-code-format = true
|
|
133
|
+
|
|
134
|
+
[tool.ruff.lint.isort]
|
|
135
|
+
section-order = [
|
|
136
|
+
"future",
|
|
137
|
+
"standard-library",
|
|
138
|
+
"pytest",
|
|
139
|
+
"numpy",
|
|
140
|
+
"third-party",
|
|
141
|
+
"first-party",
|
|
142
|
+
"local-folder",
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
[tool.mypy]
|
|
146
|
+
ignore_missing_imports = true
|