spin 0.14__tar.gz → 0.16__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.
- {spin-0.14/spin.egg-info → spin-0.16}/PKG-INFO +10 -5
- {spin-0.14 → spin-0.16}/README.md +4 -0
- {spin-0.14 → spin-0.16}/pyproject.toml +5 -4
- {spin-0.14 → spin-0.16}/spin/__init__.py +1 -1
- {spin-0.14 → spin-0.16}/spin/__main__.py +12 -15
- {spin-0.14 → spin-0.16}/spin/cmds/build.py +12 -0
- {spin-0.14 → spin-0.16}/spin/cmds/meson.py +48 -23
- {spin-0.14 → spin-0.16}/spin/cmds/pip.py +3 -1
- {spin-0.14 → spin-0.16}/spin/cmds/util.py +9 -2
- {spin-0.14 → spin-0.16}/spin/tests/test_build_cmds.py +14 -4
- {spin-0.14 → spin-0.16}/spin/tests/testutil.py +11 -2
- {spin-0.14 → spin-0.16/spin.egg-info}/PKG-INFO +10 -5
- {spin-0.14 → spin-0.16}/spin.egg-info/requires.txt +5 -2
- {spin-0.14 → spin-0.16}/LICENSE +0 -0
- {spin-0.14 → spin-0.16}/setup.cfg +0 -0
- {spin-0.14 → spin-0.16}/spin/cmds/__init__.py +0 -0
- {spin-0.14 → spin-0.16}/spin/cmds/meta.py +0 -0
- {spin-0.14 → spin-0.16}/spin/color_format.py +0 -0
- {spin-0.14 → spin-0.16}/spin/containers.py +0 -0
- {spin-0.14 → spin-0.16}/spin/sectioned_help.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/__init__.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/conftest.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/test_cli.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/test_editable.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/test_extend_command.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/test_meson.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/test_test.py +0 -0
- {spin-0.14 → spin-0.16}/spin/tests/test_util.py +0 -0
- {spin-0.14 → spin-0.16}/spin.egg-info/SOURCES.txt +0 -0
- {spin-0.14 → spin-0.16}/spin.egg-info/dependency_links.txt +0 -0
- {spin-0.14 → spin-0.16}/spin.egg-info/entry_points.txt +0 -0
- {spin-0.14 → spin-0.16}/spin.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16
|
|
4
4
|
Summary: Developer tool for scientific Python libraries
|
|
5
5
|
Maintainer-email: Scientific Python <spin@discuss.scientific-python.org>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -41,21 +41,22 @@ Classifier: Intended Audience :: Science/Research
|
|
|
41
41
|
Classifier: License :: OSI Approved :: BSD License
|
|
42
42
|
Classifier: Operating System :: OS Independent
|
|
43
43
|
Classifier: Programming Language :: Python :: 3
|
|
44
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
45
44
|
Classifier: Programming Language :: Python :: 3.10
|
|
46
45
|
Classifier: Programming Language :: Python :: 3.11
|
|
47
46
|
Classifier: Programming Language :: Python :: 3.12
|
|
48
47
|
Classifier: Programming Language :: Python :: 3.13
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
49
49
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
50
|
-
Requires-Python: >=3.
|
|
50
|
+
Requires-Python: >=3.10
|
|
51
51
|
Description-Content-Type: text/markdown
|
|
52
52
|
License-File: LICENSE
|
|
53
|
-
Requires-Dist: click
|
|
53
|
+
Requires-Dist: click<=8.2,>=8; python_version == "3.10"
|
|
54
|
+
Requires-Dist: click!=8.3.0,<8.4,>=8
|
|
54
55
|
Requires-Dist: tomli; python_version < "3.11"
|
|
55
56
|
Requires-Dist: colorama; platform_system == "Windows"
|
|
56
57
|
Requires-Dist: importlib_metadata>=7
|
|
57
58
|
Provides-Extra: lint
|
|
58
|
-
Requires-Dist: pre-commit==4.
|
|
59
|
+
Requires-Dist: pre-commit==4.3.0; extra == "lint"
|
|
59
60
|
Provides-Extra: dev
|
|
60
61
|
Requires-Dist: changelist==0.5; extra == "dev"
|
|
61
62
|
Dynamic: license-file
|
|
@@ -188,6 +189,7 @@ Available as `spin.cmds.build.*`:
|
|
|
188
189
|
|
|
189
190
|
```
|
|
190
191
|
sdist 📦 Build a source distribution in `dist/`
|
|
192
|
+
wheel 📦 Build a wheel distribution in `dist/`
|
|
191
193
|
```
|
|
192
194
|
|
|
193
195
|
### [pip](https://pip.pypa.io) (Package Installer for Python)
|
|
@@ -358,6 +360,9 @@ nox -s test -- -v
|
|
|
358
360
|
nox -s test -- -v spin/tests/test_meson.py
|
|
359
361
|
```
|
|
360
362
|
|
|
363
|
+
`spin` takes a slightly more conservative approach than [SPEC 0](https://scientific-python.org/specs/spec-0000/), and
|
|
364
|
+
supports all non-EOL versions of Python.
|
|
365
|
+
|
|
361
366
|
## History
|
|
362
367
|
|
|
363
368
|
The `dev.py` tool was [proposed for SciPy](https://github.com/scipy/scipy/issues/15489) by Ralf Gommers and [implemented](https://github.com/scipy/scipy/pull/15959) by Sayantika Banik, Eduardo Naufel Schettino, and Ralf Gommers (also see [Sayantika's blog post](https://labs.quansight.org/blog/the-evolution-of-the-scipy-developer-cli)).
|
|
@@ -126,6 +126,7 @@ Available as `spin.cmds.build.*`:
|
|
|
126
126
|
|
|
127
127
|
```
|
|
128
128
|
sdist 📦 Build a source distribution in `dist/`
|
|
129
|
+
wheel 📦 Build a wheel distribution in `dist/`
|
|
129
130
|
```
|
|
130
131
|
|
|
131
132
|
### [pip](https://pip.pypa.io) (Package Installer for Python)
|
|
@@ -296,6 +297,9 @@ nox -s test -- -v
|
|
|
296
297
|
nox -s test -- -v spin/tests/test_meson.py
|
|
297
298
|
```
|
|
298
299
|
|
|
300
|
+
`spin` takes a slightly more conservative approach than [SPEC 0](https://scientific-python.org/specs/spec-0000/), and
|
|
301
|
+
supports all non-EOL versions of Python.
|
|
302
|
+
|
|
299
303
|
## History
|
|
300
304
|
|
|
301
305
|
The `dev.py` tool was [proposed for SciPy](https://github.com/scipy/scipy/issues/15489) by Ralf Gommers and [implemented](https://github.com/scipy/scipy/pull/15959) by Sayantika Banik, Eduardo Naufel Schettino, and Ralf Gommers (also see [Sayantika's blog post](https://labs.quansight.org/blog/the-evolution-of-the-scipy-developer-cli)).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "spin"
|
|
3
|
-
requires-python = ">=3.
|
|
3
|
+
requires-python = ">=3.10" # Oldest non-EOL Python here
|
|
4
4
|
description = "Developer tool for scientific Python libraries"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {file = "LICENSE"}
|
|
@@ -15,15 +15,16 @@ classifiers = [
|
|
|
15
15
|
"License :: OSI Approved :: BSD License",
|
|
16
16
|
"Operating System :: OS Independent",
|
|
17
17
|
"Programming Language :: Python :: 3",
|
|
18
|
-
"Programming Language :: Python :: 3.9",
|
|
19
18
|
"Programming Language :: Python :: 3.10",
|
|
20
19
|
"Programming Language :: Python :: 3.11",
|
|
21
20
|
"Programming Language :: Python :: 3.12",
|
|
22
21
|
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
23
|
"Programming Language :: Python :: 3 :: Only",
|
|
24
24
|
]
|
|
25
25
|
dependencies = [
|
|
26
|
-
"click",
|
|
26
|
+
"click>=8,<=8.2; python_version == '3.10'", # cannot deepcopy cmd params (specifically, Sentinel.UNSET) on 3.10
|
|
27
|
+
"click>=8,!=8.3.0,<8.4",
|
|
27
28
|
"tomli; python_version < '3.11'",
|
|
28
29
|
"colorama; platform_system == 'Windows'",
|
|
29
30
|
"importlib_metadata >= 7"
|
|
@@ -34,7 +35,7 @@ dynamic = ['version']
|
|
|
34
35
|
spin = "spin.__main__:main"
|
|
35
36
|
|
|
36
37
|
[project.optional-dependencies]
|
|
37
|
-
lint = ["pre-commit == 4.
|
|
38
|
+
lint = ["pre-commit == 4.3.0"]
|
|
38
39
|
dev = ["changelist == 0.5"]
|
|
39
40
|
|
|
40
41
|
[project.urls]
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import collections
|
|
2
2
|
import importlib
|
|
3
3
|
import importlib.util
|
|
4
|
-
import inspect
|
|
5
4
|
import os
|
|
6
5
|
import pathlib
|
|
7
6
|
import sys
|
|
8
7
|
import textwrap
|
|
9
|
-
|
|
8
|
+
import traceback
|
|
10
9
|
|
|
11
10
|
import click
|
|
12
11
|
|
|
@@ -31,7 +30,7 @@ config_filenames = (
|
|
|
31
30
|
)
|
|
32
31
|
|
|
33
32
|
|
|
34
|
-
def _detect_config_dir(path: pathlib.Path) ->
|
|
33
|
+
def _detect_config_dir(path: pathlib.Path) -> pathlib.Path | None:
|
|
35
34
|
path = path.resolve()
|
|
36
35
|
files = os.listdir(path)
|
|
37
36
|
if any(f in files for f in config_filenames):
|
|
@@ -199,17 +198,16 @@ def main():
|
|
|
199
198
|
|
|
200
199
|
try:
|
|
201
200
|
group()
|
|
202
|
-
except Exception
|
|
201
|
+
except Exception:
|
|
203
202
|
click.secho(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
This exception was raised from:
|
|
210
|
-
|
|
211
|
-
{inspect.trace()[-1].filename}
|
|
203
|
+
"\n" + "".join(traceback.format_exception(*sys.exc_info(), limit=-1)),
|
|
204
|
+
fg="red",
|
|
205
|
+
bold=True,
|
|
206
|
+
file=sys.stderr,
|
|
207
|
+
)
|
|
212
208
|
|
|
209
|
+
click.secho(
|
|
210
|
+
textwrap.dedent(f"""\
|
|
213
211
|
If you suspect this is a bug in `spin`, please file a report at:
|
|
214
212
|
|
|
215
213
|
https://github.com/scientific-python/spin
|
|
@@ -218,9 +216,8 @@ def main():
|
|
|
218
216
|
|
|
219
217
|
spin: {__version__}, package: {proj_name}
|
|
220
218
|
|
|
221
|
-
Aborting."""
|
|
222
|
-
|
|
223
|
-
fg="red",
|
|
219
|
+
Aborting."""),
|
|
220
|
+
fg="yellow",
|
|
224
221
|
bold=True,
|
|
225
222
|
file=sys.stderr,
|
|
226
223
|
)
|
|
@@ -13,3 +13,15 @@ def sdist(pyproject_build_args):
|
|
|
13
13
|
spin sdist -- -x -n
|
|
14
14
|
"""
|
|
15
15
|
run(["pyproject-build", ".", "--sdist"] + list(pyproject_build_args))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.command()
|
|
19
|
+
@click.argument("pyproject-build-args", metavar="", nargs=-1)
|
|
20
|
+
def wheel(pyproject_build_args):
|
|
21
|
+
"""📦 Build a wheel distribution in `dist/`
|
|
22
|
+
|
|
23
|
+
Extra arguments are passed to `pyproject-build`, e.g.
|
|
24
|
+
|
|
25
|
+
spin wheel -- -x -n
|
|
26
|
+
"""
|
|
27
|
+
run(["pyproject-build", ".", "--wheel"] + list(pyproject_build_args))
|
|
@@ -35,7 +35,15 @@ def _meson_cli():
|
|
|
35
35
|
return [meson_cli]
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def editable_install_path(distname: str) -> str | None:
|
|
39
|
+
"""Return path of the editable install for package `distname`.
|
|
40
|
+
|
|
41
|
+
If the package is not an editable install, return None.
|
|
42
|
+
|
|
43
|
+
See Also
|
|
44
|
+
--------
|
|
45
|
+
is_editable_install
|
|
46
|
+
"""
|
|
39
47
|
import importlib_metadata
|
|
40
48
|
|
|
41
49
|
try:
|
|
@@ -57,16 +65,34 @@ def _editable_install_path(distname):
|
|
|
57
65
|
return None
|
|
58
66
|
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
# backward compat
|
|
69
|
+
_editable_install_path = editable_install_path
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def is_editable_install(distname: str, verify_path: bool = False) -> bool:
|
|
73
|
+
"""Whether or not an editable install of `distname` is present.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
`distname` : str
|
|
78
|
+
Name of the package. E.g., ``numpy`` or ``scikit-image``.
|
|
79
|
+
Not always the same as the module name (``numpy`` and
|
|
80
|
+
``skimage`` for the above).
|
|
81
|
+
"""
|
|
82
|
+
return editable_install_path(distname) is not None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# backward compat
|
|
86
|
+
_is_editable_install = is_editable_install
|
|
62
87
|
|
|
63
88
|
|
|
64
|
-
def _is_editable_install_of_same_source(distname):
|
|
65
|
-
|
|
66
|
-
|
|
89
|
+
def _is_editable_install_of_same_source(distname: str) -> bool:
|
|
90
|
+
"""Check whether the editable install was made from the current directory."""
|
|
91
|
+
editable_path = editable_install_path(distname)
|
|
92
|
+
return (editable_path is not None) and os.path.samefile(editable_path, ".")
|
|
67
93
|
|
|
68
94
|
|
|
69
|
-
def _set_pythonpath(build_dir, quiet=False):
|
|
95
|
+
def _set_pythonpath(build_dir: str, quiet: bool = False) -> str:
|
|
70
96
|
"""Set first entry of PYTHONPATH to site packages directory.
|
|
71
97
|
|
|
72
98
|
For editable installs, leave the PYTHONPATH alone.
|
|
@@ -78,12 +104,12 @@ def _set_pythonpath(build_dir, quiet=False):
|
|
|
78
104
|
cfg = get_config()
|
|
79
105
|
distname = cfg.get("project.name", None)
|
|
80
106
|
if distname:
|
|
81
|
-
if
|
|
107
|
+
if is_editable_install(distname):
|
|
82
108
|
if _is_editable_install_of_same_source(distname):
|
|
83
109
|
if not (quiet):
|
|
84
110
|
click.secho(
|
|
85
111
|
"Editable install of same source directory detected; not setting PYTHONPATH",
|
|
86
|
-
fg="
|
|
112
|
+
fg="yellow",
|
|
87
113
|
)
|
|
88
114
|
return ""
|
|
89
115
|
else:
|
|
@@ -114,11 +140,11 @@ def _set_pythonpath(build_dir, quiet=False):
|
|
|
114
140
|
return site_packages
|
|
115
141
|
|
|
116
142
|
|
|
117
|
-
def _get_install_dir(build_dir):
|
|
143
|
+
def _get_install_dir(build_dir: str) -> str:
|
|
118
144
|
return f"{build_dir}-install"
|
|
119
145
|
|
|
120
146
|
|
|
121
|
-
def _get_site_packages(build_dir):
|
|
147
|
+
def _get_site_packages(build_dir: str) -> str:
|
|
122
148
|
install_dir = _get_install_dir(build_dir)
|
|
123
149
|
try:
|
|
124
150
|
cfg = get_config()
|
|
@@ -140,13 +166,12 @@ def _get_site_packages(build_dir):
|
|
|
140
166
|
site_packages = None
|
|
141
167
|
if any(f"python{X}." in p for p in candidate_paths):
|
|
142
168
|
# We have a system that uses `python3.X/site-packages` or `python3.X/dist-packages`
|
|
143
|
-
|
|
144
|
-
if len(
|
|
169
|
+
site_packages_paths = [p for p in candidate_paths if f"python{X}.{Y}" in p]
|
|
170
|
+
if len(site_packages_paths) == 0:
|
|
145
171
|
raise FileNotFoundError(
|
|
146
172
|
f"No site-packages found in {install_dir} for Python {X}.{Y}"
|
|
147
173
|
)
|
|
148
|
-
|
|
149
|
-
site_packages = site_packages[0]
|
|
174
|
+
site_packages = site_packages_paths[0]
|
|
150
175
|
else:
|
|
151
176
|
# A naming scheme that does not encode the Python major/minor version is used, so return
|
|
152
177
|
# whatever site-packages path was found
|
|
@@ -165,22 +190,22 @@ def _get_site_packages(build_dir):
|
|
|
165
190
|
return site_packages
|
|
166
191
|
|
|
167
192
|
|
|
168
|
-
def _meson_version():
|
|
193
|
+
def _meson_version() -> str | None:
|
|
169
194
|
try:
|
|
170
195
|
p = _run(_meson_cli() + ["--version"], output=False, echo=False)
|
|
171
196
|
return p.stdout.decode("ascii").strip()
|
|
172
197
|
except:
|
|
173
|
-
|
|
198
|
+
return None
|
|
174
199
|
|
|
175
200
|
|
|
176
|
-
def _meson_version_configured(build_dir):
|
|
201
|
+
def _meson_version_configured(build_dir: str) -> str | None:
|
|
177
202
|
try:
|
|
178
203
|
meson_info_fn = os.path.join(build_dir, "meson-info", "meson-info.json")
|
|
179
204
|
with open(meson_info_fn) as f:
|
|
180
205
|
meson_info = json.load(f)
|
|
181
206
|
return meson_info["meson_version"]["full"]
|
|
182
207
|
except:
|
|
183
|
-
|
|
208
|
+
return None
|
|
184
209
|
|
|
185
210
|
|
|
186
211
|
def _meson_coverage_configured() -> bool:
|
|
@@ -199,7 +224,7 @@ def _meson_coverage_configured() -> bool:
|
|
|
199
224
|
return False
|
|
200
225
|
|
|
201
226
|
|
|
202
|
-
def _check_coverage_tool_installation(coverage_type: GcovReportFormat, build_dir):
|
|
227
|
+
def _check_coverage_tool_installation(coverage_type: GcovReportFormat, build_dir: str):
|
|
203
228
|
requirements = { # https://github.com/mesonbuild/meson/blob/6e381714c7cb15877e2bcaa304b93c212252ada3/docs/markdown/Unit-tests.md?plain=1#L49-L62
|
|
204
229
|
GcovReportFormat.html: ["Gcovr/GenHTML", "lcov"],
|
|
205
230
|
GcovReportFormat.xml: ["Gcovr (version 3.3 or higher)"],
|
|
@@ -336,7 +361,7 @@ def build(
|
|
|
336
361
|
if not quiet:
|
|
337
362
|
click.secho(
|
|
338
363
|
"Editable install of same source detected; skipping build",
|
|
339
|
-
fg="
|
|
364
|
+
fg="yellow",
|
|
340
365
|
)
|
|
341
366
|
return
|
|
342
367
|
|
|
@@ -419,7 +444,7 @@ def _get_configured_command(command_name):
|
|
|
419
444
|
metavar="N_JOBS",
|
|
420
445
|
default="1",
|
|
421
446
|
help=(
|
|
422
|
-
"Number of parallel jobs for testing. Can be set to `auto` to use all cores."
|
|
447
|
+
"Number of parallel jobs for testing with pytest-xdist. Can be set to `auto` to use all cores."
|
|
423
448
|
),
|
|
424
449
|
)
|
|
425
450
|
@click.option(
|
|
@@ -487,7 +512,7 @@ def test(
|
|
|
487
512
|
|
|
488
513
|
To run test modules, functions, classes, or methods:
|
|
489
514
|
|
|
490
|
-
spin -t numpy.random
|
|
515
|
+
spin test -t numpy.random
|
|
491
516
|
|
|
492
517
|
To report the durations of the N slowest tests:
|
|
493
518
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
1
3
|
import click
|
|
2
4
|
|
|
3
5
|
from .util import run as _run
|
|
@@ -37,7 +39,7 @@ def install(*, pip_args, editable, verbose, verbose_import):
|
|
|
37
39
|
pip install . --no-build-isolation --editable --no-clean
|
|
38
40
|
"""
|
|
39
41
|
pip_args = list(pip_args)
|
|
40
|
-
pip_cmd = ["pip", "install"]
|
|
42
|
+
pip_cmd = [sys.executable, "-m", "pip", "install"]
|
|
41
43
|
pip_args += ["--no-build-isolation"]
|
|
42
44
|
|
|
43
45
|
if editable:
|
|
@@ -127,7 +127,14 @@ def extend_command(
|
|
|
127
127
|
Command to extend.
|
|
128
128
|
doc : str
|
|
129
129
|
Replacement docstring.
|
|
130
|
-
The
|
|
130
|
+
The decorated function's docstring is also appended.
|
|
131
|
+
This is done so that two modes of documenting are enabled:
|
|
132
|
+
|
|
133
|
+
1. Extend original command documentation.
|
|
134
|
+
Do this by providing a docstring on the decorated function.
|
|
135
|
+
2. Replace the original command's documentation.
|
|
136
|
+
Do this either by setting ``doc`` to a docstring, or by
|
|
137
|
+
setting ``doc=''`` and adding a docstring to the decorated function.
|
|
131
138
|
remove_args : tuple of str
|
|
132
139
|
List of arguments to remove from the parent command.
|
|
133
140
|
These arguments can still be set explicitly by calling
|
|
@@ -168,7 +175,7 @@ def extend_command(
|
|
|
168
175
|
return user_func(*args, parent_callback=parent_cmd, **kwargs)
|
|
169
176
|
|
|
170
177
|
my_cmd.callback = click.pass_context(callback_with_parent_callback)
|
|
171
|
-
my_cmd.callback._parent = user_func
|
|
178
|
+
my_cmd.callback._parent = user_func # type: ignore[attr-defined]
|
|
172
179
|
|
|
173
180
|
if doc is not None:
|
|
174
181
|
my_cmd.help = doc
|
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
import subprocess
|
|
3
3
|
import sys
|
|
4
4
|
import tempfile
|
|
5
|
-
from pathlib import Path
|
|
5
|
+
from pathlib import Path, PureWindowsPath
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
8
|
|
|
@@ -19,6 +19,10 @@ from .testutil import (
|
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
def unix_path(p: str) -> str:
|
|
23
|
+
return PureWindowsPath(p).as_posix()
|
|
24
|
+
|
|
25
|
+
|
|
22
26
|
def test_basic_build(example_pkg):
|
|
23
27
|
"""Does the package build?"""
|
|
24
28
|
spin("build")
|
|
@@ -39,7 +43,7 @@ def test_debug_builds(example_pkg):
|
|
|
39
43
|
|
|
40
44
|
def test_prefix_builds(example_pkg):
|
|
41
45
|
"""does spin build --prefix create a build-install directory with the correct structure?"""
|
|
42
|
-
spin("build", "--prefix
|
|
46
|
+
spin("build", f"--prefix={os.path.abspath('/foobar')}")
|
|
43
47
|
assert (Path("build-install") / Path("foobar")).exists()
|
|
44
48
|
|
|
45
49
|
|
|
@@ -116,6 +120,12 @@ def test_sdist(example_pkg):
|
|
|
116
120
|
spin("sdist")
|
|
117
121
|
|
|
118
122
|
|
|
123
|
+
def test_wheel(example_pkg):
|
|
124
|
+
spin("wheel")
|
|
125
|
+
wheel_file_list = list(Path("dist").glob("example_pkg-0.0.dev0-*.whl"))
|
|
126
|
+
assert len(wheel_file_list) == 1, "Wheel file not created in dist/"
|
|
127
|
+
|
|
128
|
+
|
|
119
129
|
def test_example(example_pkg):
|
|
120
130
|
spin("example")
|
|
121
131
|
|
|
@@ -178,7 +188,7 @@ def test_parallel_builds(example_pkg):
|
|
|
178
188
|
spin("build")
|
|
179
189
|
spin("build", "-C", "parallel/build")
|
|
180
190
|
p = spin("python", "--", "-c", "import example_pkg; print(example_pkg.__file__)")
|
|
181
|
-
example_pkg_path = stdout(p).split("\n")[-1]
|
|
191
|
+
example_pkg_path = unix_path(stdout(p).split("\n")[-1])
|
|
182
192
|
p = spin(
|
|
183
193
|
"python",
|
|
184
194
|
"-C",
|
|
@@ -187,7 +197,7 @@ def test_parallel_builds(example_pkg):
|
|
|
187
197
|
"-c",
|
|
188
198
|
"import example_pkg; print(example_pkg.__file__)",
|
|
189
199
|
)
|
|
190
|
-
example_pkg_parallel_path = stdout(p).split("\n")[-1]
|
|
200
|
+
example_pkg_parallel_path = unix_path(stdout(p).split("\n")[-1])
|
|
191
201
|
assert "build-install" in example_pkg_path
|
|
192
202
|
assert "parallel/build-install" in example_pkg_parallel_path
|
|
193
203
|
assert "parallel/build-install" not in example_pkg_path
|
|
@@ -24,12 +24,21 @@ skip_py_lt_311 = pytest.mark.skipif(
|
|
|
24
24
|
|
|
25
25
|
def spin(*args, **user_kwargs):
|
|
26
26
|
args = (str(el) for el in args)
|
|
27
|
+
# Capture stdout, stderr separately
|
|
27
28
|
default_kwargs = {
|
|
28
29
|
"stdout": subprocess.PIPE,
|
|
29
30
|
"stderr": subprocess.PIPE,
|
|
30
|
-
"sys_exit":
|
|
31
|
+
"sys_exit": False,
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
p = run(["spin"] + list(args), **{**default_kwargs, **user_kwargs})
|
|
34
|
+
if p.returncode != 0:
|
|
35
|
+
print(p.stdout.decode("utf-8"), end="")
|
|
36
|
+
print(p.stderr.decode("utf-8"), end="")
|
|
37
|
+
# Exit unless the spin call explicitly asks us not to
|
|
38
|
+
# by setting sys_exit=False
|
|
39
|
+
if user_kwargs.get("sys_exit", True):
|
|
40
|
+
sys.exit(p.returncode)
|
|
41
|
+
return p
|
|
33
42
|
|
|
34
43
|
|
|
35
44
|
def stdout(p):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16
|
|
4
4
|
Summary: Developer tool for scientific Python libraries
|
|
5
5
|
Maintainer-email: Scientific Python <spin@discuss.scientific-python.org>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -41,21 +41,22 @@ Classifier: Intended Audience :: Science/Research
|
|
|
41
41
|
Classifier: License :: OSI Approved :: BSD License
|
|
42
42
|
Classifier: Operating System :: OS Independent
|
|
43
43
|
Classifier: Programming Language :: Python :: 3
|
|
44
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
45
44
|
Classifier: Programming Language :: Python :: 3.10
|
|
46
45
|
Classifier: Programming Language :: Python :: 3.11
|
|
47
46
|
Classifier: Programming Language :: Python :: 3.12
|
|
48
47
|
Classifier: Programming Language :: Python :: 3.13
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
49
49
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
50
|
-
Requires-Python: >=3.
|
|
50
|
+
Requires-Python: >=3.10
|
|
51
51
|
Description-Content-Type: text/markdown
|
|
52
52
|
License-File: LICENSE
|
|
53
|
-
Requires-Dist: click
|
|
53
|
+
Requires-Dist: click<=8.2,>=8; python_version == "3.10"
|
|
54
|
+
Requires-Dist: click!=8.3.0,<8.4,>=8
|
|
54
55
|
Requires-Dist: tomli; python_version < "3.11"
|
|
55
56
|
Requires-Dist: colorama; platform_system == "Windows"
|
|
56
57
|
Requires-Dist: importlib_metadata>=7
|
|
57
58
|
Provides-Extra: lint
|
|
58
|
-
Requires-Dist: pre-commit==4.
|
|
59
|
+
Requires-Dist: pre-commit==4.3.0; extra == "lint"
|
|
59
60
|
Provides-Extra: dev
|
|
60
61
|
Requires-Dist: changelist==0.5; extra == "dev"
|
|
61
62
|
Dynamic: license-file
|
|
@@ -188,6 +189,7 @@ Available as `spin.cmds.build.*`:
|
|
|
188
189
|
|
|
189
190
|
```
|
|
190
191
|
sdist 📦 Build a source distribution in `dist/`
|
|
192
|
+
wheel 📦 Build a wheel distribution in `dist/`
|
|
191
193
|
```
|
|
192
194
|
|
|
193
195
|
### [pip](https://pip.pypa.io) (Package Installer for Python)
|
|
@@ -358,6 +360,9 @@ nox -s test -- -v
|
|
|
358
360
|
nox -s test -- -v spin/tests/test_meson.py
|
|
359
361
|
```
|
|
360
362
|
|
|
363
|
+
`spin` takes a slightly more conservative approach than [SPEC 0](https://scientific-python.org/specs/spec-0000/), and
|
|
364
|
+
supports all non-EOL versions of Python.
|
|
365
|
+
|
|
361
366
|
## History
|
|
362
367
|
|
|
363
368
|
The `dev.py` tool was [proposed for SciPy](https://github.com/scipy/scipy/issues/15489) by Ralf Gommers and [implemented](https://github.com/scipy/scipy/pull/15959) by Sayantika Banik, Eduardo Naufel Schettino, and Ralf Gommers (also see [Sayantika's blog post](https://labs.quansight.org/blog/the-evolution-of-the-scipy-developer-cli)).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
click
|
|
1
|
+
click!=8.3.0,<8.4,>=8
|
|
2
2
|
importlib_metadata>=7
|
|
3
3
|
|
|
4
4
|
[:platform_system == "Windows"]
|
|
@@ -7,8 +7,11 @@ colorama
|
|
|
7
7
|
[:python_version < "3.11"]
|
|
8
8
|
tomli
|
|
9
9
|
|
|
10
|
+
[:python_version == "3.10"]
|
|
11
|
+
click<=8.2,>=8
|
|
12
|
+
|
|
10
13
|
[dev]
|
|
11
14
|
changelist==0.5
|
|
12
15
|
|
|
13
16
|
[lint]
|
|
14
|
-
pre-commit==4.
|
|
17
|
+
pre-commit==4.3.0
|
{spin-0.14 → spin-0.16}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|