spin 0.7__tar.gz → 0.9__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.
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2021--2022, Scientific Python project
3
+ Copyright (c) 2021--2024, Scientific Python project
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spin
3
- Version: 0.7
3
+ Version: 0.9
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
7
7
 
8
- Copyright (c) 2021--2022, Scientific Python project
8
+ Copyright (c) 2021--2024, Scientific Python project
9
9
  All rights reserved.
10
10
 
11
11
  Redistribution and use in source and binary forms, with or without
@@ -41,40 +41,40 @@ 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.7
45
44
  Classifier: Programming Language :: Python :: 3.8
46
45
  Classifier: Programming Language :: Python :: 3.9
47
46
  Classifier: Programming Language :: Python :: 3.10
48
47
  Classifier: Programming Language :: Python :: 3.11
49
48
  Classifier: Programming Language :: Python :: 3.12
50
49
  Classifier: Programming Language :: Python :: 3 :: Only
51
- Requires-Python: >=3.7
50
+ Requires-Python: >=3.8
52
51
  Description-Content-Type: text/markdown
53
52
  License-File: LICENSE
54
53
  Requires-Dist: click
55
54
  Requires-Dist: tomli; python_version < "3.11"
56
55
  Requires-Dist: colorama; platform_system == "Windows"
56
+ Requires-Dist: importlib_metadata>=7
57
57
  Provides-Extra: lint
58
- Requires-Dist: pre-commit==3.4.0; extra == "lint"
58
+ Requires-Dist: pre-commit==3.7.0; extra == "lint"
59
59
  Provides-Extra: dev
60
- Requires-Dist: changelist==0.3; extra == "dev"
60
+ Requires-Dist: changelist==0.5; extra == "dev"
61
61
 
62
62
  # 💫 Scientific Python INcantations (`spin`)
63
63
 
64
64
  ## A developer tool for scientific Python libraries
65
65
 
66
- **NOTE:** If you are looking for `devpy`, this is it! We had to rename
67
- the package to publish it on PyPi.
68
-
69
66
  Developers need to memorize a whole bunch of magic command-line incantations.
70
- And these incantations change from time to time!
71
- Typically, their lives are made simpler by a Makefile, but Makefiles can be convoluted, are not written in Python, and are hard to extend.
72
- The rationale behind `spin` is therefore to provide a simple interface for common development tasks.
67
+ These incantations may also change over time.
68
+ Often, Makefiles are used to provide aliases, but Makefiles can be convoluted, are not written in Python, and are hard to extend.
69
+ The goal of `spin` is therefore to provide a simple, user-friendly, extendable interface for common development tasks.
73
70
  It comes with a few common build commands out the box, but can easily be customized per project.
74
71
 
75
72
  As a curiosity: the impetus behind developing the tool was the mass migration of scientific Python libraries (SciPy, scikit-image, and NumPy, etc.) to Meson, after distutils was deprecated.
76
73
  When many of the build and installation commands changed, it made sense to abstract away the nuisance of having to re-learn them.
77
74
 
75
+ _Note:_ We now have experimental builds for editable installs.
76
+ Most of the Meson commands listed below should work "out of the box" for those.
77
+
78
78
  ## Installation
79
79
 
80
80
  ```
@@ -83,9 +83,10 @@ pip install spin
83
83
 
84
84
  ## Configuration
85
85
 
86
- Settings are in your project's `pyproject.toml`.
86
+ Settings are stored in `.spin.toml`, `spin.toml`, or your project's `pyproject.toml`.
87
87
  As an example, see the `[tool.spin]` section of [an example `pyproject.toml`](https://github.com/scientific-python/spin/blob/main/example_pkg/pyproject.toml).
88
88
 
89
+ The `[project]` section should contain `name`.
89
90
  The `[tool.spin]` section should contain:
90
91
 
91
92
  ```
@@ -143,6 +144,8 @@ python -m spin
143
144
 
144
145
  ### [Meson](https://meson-python.readthedocs.io)
145
146
 
147
+ Available as `spin.cmds.meson.*`.
148
+
146
149
  ```
147
150
  build 🔧 Build package with Meson/ninja and install to `build-install`
148
151
  ipython 💻 Launch IPython shell with PYTHONPATH set
@@ -151,17 +154,32 @@ python -m spin
151
154
  test 🔧 Run pytest
152
155
  run 🏁 Run a shell command with PYTHONPATH set
153
156
  docs 📖 Build Sphinx documentation
154
- gdb 👾 Execute a Python snippet with GDB
157
+ gdb 👾 Execute a Python snippet with GDB
158
+ lldb 👾 Execute a Python snippet with LLDB
155
159
  ```
156
160
 
157
161
  ### [Build](https://pypa-build.readthedocs.io/en/stable/) (PEP 517 builder)
158
162
 
159
- `spin` was started with Meson in mind, but we're working on expanding commands for PEP 517 `build`.
163
+ Available as `spin.cmds.build.*`:
160
164
 
161
165
  ```
162
166
  sdist 📦 Build a source distribution in `dist/`
163
167
  ```
164
168
 
169
+ ### [pip](https://pip.pypa.io) (Package Installer for Python)
170
+
171
+ `pip` allows for editable installs, another common
172
+ development workflow.
173
+
174
+ Note that, for now, the meson commands above do not work with an
175
+ editable install of the package. We're [working on changing that](https://github.com/scientific-python/spin/pull/141).
176
+
177
+ Available as `spin.cmds.pip.*`:
178
+
179
+ ```
180
+ install 💽 Build and install package using pip.
181
+ ```
182
+
165
183
  ## 🧪 Custom commands
166
184
 
167
185
  `spin` can invoke custom commands. These commands define their own arguments, and have access to the `pyproject.toml` file for further configuration.
@@ -192,6 +210,29 @@ def example():
192
210
  print(config["tool.spin"])
193
211
  ```
194
212
 
213
+ ### Argument overrides
214
+
215
+ Default arguments can be overridden for any command.
216
+ The custom command above, e.g., has the following signature:
217
+
218
+ ```python
219
+ @click.command()
220
+ @click.option("-f", "--flag")
221
+ @click.option("-t", "--test", default="not set")
222
+ def example(flag, test, default_kwd=None):
223
+ """🧪 Example custom command.
224
+ ...
225
+ """
226
+ ```
227
+
228
+ Use the `[tool.spin.kwargs]` section to override default values for
229
+ click options or function keywords:
230
+
231
+ ```toml
232
+ [tool.spin.kwargs]
233
+ ".spin/cmds.py:example" = {"test" = "default override", "default_kwd" = 3}
234
+ ```
235
+
195
236
  ### Advanced: adding arguments to built-in commands
196
237
 
197
238
  Instead of rewriting a command from scratch, a project may want to add a flag to a built-in `spin` command, or perhaps do some pre- or post-processing.
@@ -251,6 +292,27 @@ Meson CLI can be set in `pyproject.toml`:
251
292
  cli = 'path/to/custom/meson'
252
293
  ```
253
294
 
295
+ ## FAQ
296
+
297
+ - Running `spin`, the emojis in the command list don't show up.
298
+
299
+ Your terminal font may not include emoji characters. E.g., if you use
300
+ noto on Arch Linux the emojis are installed separately:
301
+
302
+ ```sh
303
+ sudo pacman -S noto-fonts-emoji
304
+ fc-cache -f -v
305
+ ```
306
+
307
+ ## For contributors
308
+
309
+ `spin` development happens on GitHub at [scientific-python/spin](https://github.com/scientific-python/spin).
310
+ `spin` tests are invoked using:
311
+
312
+ ```
313
+ nox -s test
314
+ ```
315
+
254
316
  ## History
255
317
 
256
318
  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)).
@@ -2,18 +2,18 @@
2
2
 
3
3
  ## A developer tool for scientific Python libraries
4
4
 
5
- **NOTE:** If you are looking for `devpy`, this is it! We had to rename
6
- the package to publish it on PyPi.
7
-
8
5
  Developers need to memorize a whole bunch of magic command-line incantations.
9
- And these incantations change from time to time!
10
- Typically, their lives are made simpler by a Makefile, but Makefiles can be convoluted, are not written in Python, and are hard to extend.
11
- The rationale behind `spin` is therefore to provide a simple interface for common development tasks.
6
+ These incantations may also change over time.
7
+ Often, Makefiles are used to provide aliases, but Makefiles can be convoluted, are not written in Python, and are hard to extend.
8
+ The goal of `spin` is therefore to provide a simple, user-friendly, extendable interface for common development tasks.
12
9
  It comes with a few common build commands out the box, but can easily be customized per project.
13
10
 
14
11
  As a curiosity: the impetus behind developing the tool was the mass migration of scientific Python libraries (SciPy, scikit-image, and NumPy, etc.) to Meson, after distutils was deprecated.
15
12
  When many of the build and installation commands changed, it made sense to abstract away the nuisance of having to re-learn them.
16
13
 
14
+ _Note:_ We now have experimental builds for editable installs.
15
+ Most of the Meson commands listed below should work "out of the box" for those.
16
+
17
17
  ## Installation
18
18
 
19
19
  ```
@@ -22,9 +22,10 @@ pip install spin
22
22
 
23
23
  ## Configuration
24
24
 
25
- Settings are in your project's `pyproject.toml`.
25
+ Settings are stored in `.spin.toml`, `spin.toml`, or your project's `pyproject.toml`.
26
26
  As an example, see the `[tool.spin]` section of [an example `pyproject.toml`](https://github.com/scientific-python/spin/blob/main/example_pkg/pyproject.toml).
27
27
 
28
+ The `[project]` section should contain `name`.
28
29
  The `[tool.spin]` section should contain:
29
30
 
30
31
  ```
@@ -82,6 +83,8 @@ python -m spin
82
83
 
83
84
  ### [Meson](https://meson-python.readthedocs.io)
84
85
 
86
+ Available as `spin.cmds.meson.*`.
87
+
85
88
  ```
86
89
  build 🔧 Build package with Meson/ninja and install to `build-install`
87
90
  ipython 💻 Launch IPython shell with PYTHONPATH set
@@ -90,17 +93,32 @@ python -m spin
90
93
  test 🔧 Run pytest
91
94
  run 🏁 Run a shell command with PYTHONPATH set
92
95
  docs 📖 Build Sphinx documentation
93
- gdb 👾 Execute a Python snippet with GDB
96
+ gdb 👾 Execute a Python snippet with GDB
97
+ lldb 👾 Execute a Python snippet with LLDB
94
98
  ```
95
99
 
96
100
  ### [Build](https://pypa-build.readthedocs.io/en/stable/) (PEP 517 builder)
97
101
 
98
- `spin` was started with Meson in mind, but we're working on expanding commands for PEP 517 `build`.
102
+ Available as `spin.cmds.build.*`:
99
103
 
100
104
  ```
101
105
  sdist 📦 Build a source distribution in `dist/`
102
106
  ```
103
107
 
108
+ ### [pip](https://pip.pypa.io) (Package Installer for Python)
109
+
110
+ `pip` allows for editable installs, another common
111
+ development workflow.
112
+
113
+ Note that, for now, the meson commands above do not work with an
114
+ editable install of the package. We're [working on changing that](https://github.com/scientific-python/spin/pull/141).
115
+
116
+ Available as `spin.cmds.pip.*`:
117
+
118
+ ```
119
+ install 💽 Build and install package using pip.
120
+ ```
121
+
104
122
  ## 🧪 Custom commands
105
123
 
106
124
  `spin` can invoke custom commands. These commands define their own arguments, and have access to the `pyproject.toml` file for further configuration.
@@ -131,6 +149,29 @@ def example():
131
149
  print(config["tool.spin"])
132
150
  ```
133
151
 
152
+ ### Argument overrides
153
+
154
+ Default arguments can be overridden for any command.
155
+ The custom command above, e.g., has the following signature:
156
+
157
+ ```python
158
+ @click.command()
159
+ @click.option("-f", "--flag")
160
+ @click.option("-t", "--test", default="not set")
161
+ def example(flag, test, default_kwd=None):
162
+ """🧪 Example custom command.
163
+ ...
164
+ """
165
+ ```
166
+
167
+ Use the `[tool.spin.kwargs]` section to override default values for
168
+ click options or function keywords:
169
+
170
+ ```toml
171
+ [tool.spin.kwargs]
172
+ ".spin/cmds.py:example" = {"test" = "default override", "default_kwd" = 3}
173
+ ```
174
+
134
175
  ### Advanced: adding arguments to built-in commands
135
176
 
136
177
  Instead of rewriting a command from scratch, a project may want to add a flag to a built-in `spin` command, or perhaps do some pre- or post-processing.
@@ -190,6 +231,27 @@ Meson CLI can be set in `pyproject.toml`:
190
231
  cli = 'path/to/custom/meson'
191
232
  ```
192
233
 
234
+ ## FAQ
235
+
236
+ - Running `spin`, the emojis in the command list don't show up.
237
+
238
+ Your terminal font may not include emoji characters. E.g., if you use
239
+ noto on Arch Linux the emojis are installed separately:
240
+
241
+ ```sh
242
+ sudo pacman -S noto-fonts-emoji
243
+ fc-cache -f -v
244
+ ```
245
+
246
+ ## For contributors
247
+
248
+ `spin` development happens on GitHub at [scientific-python/spin](https://github.com/scientific-python/spin).
249
+ `spin` tests are invoked using:
250
+
251
+ ```
252
+ nox -s test
253
+ ```
254
+
193
255
  ## History
194
256
 
195
257
  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,7 +1,6 @@
1
1
  [project]
2
2
  name = "spin"
3
- version = "0.7"
4
- requires-python = ">=3.7"
3
+ requires-python = ">=3.8"
5
4
  description = "Developer tool for scientific Python libraries"
6
5
  readme = "README.md"
7
6
  license = {file = "LICENSE"}
@@ -16,7 +15,6 @@ classifiers = [
16
15
  "License :: OSI Approved :: BSD License",
17
16
  "Operating System :: OS Independent",
18
17
  "Programming Language :: Python :: 3",
19
- "Programming Language :: Python :: 3.7",
20
18
  "Programming Language :: Python :: 3.8",
21
19
  "Programming Language :: Python :: 3.9",
22
20
  "Programming Language :: Python :: 3.10",
@@ -27,19 +25,24 @@ classifiers = [
27
25
  dependencies = [
28
26
  "click",
29
27
  "tomli; python_version < '3.11'",
30
- "colorama; platform_system == 'Windows'"
28
+ "colorama; platform_system == 'Windows'",
29
+ "importlib_metadata >= 7"
31
30
  ]
31
+ dynamic = ['version']
32
32
 
33
33
  [project.scripts]
34
34
  spin = "spin.__main__:main"
35
35
 
36
36
  [project.optional-dependencies]
37
- lint = ["pre-commit == 3.4.0"]
38
- dev = ["changelist == 0.3"]
37
+ lint = ["pre-commit == 3.7.0"]
38
+ dev = ["changelist == 0.5"]
39
39
 
40
40
  [project.urls]
41
41
  homepage = "https://github.com/scientific-python/spin"
42
42
 
43
+ [tool.setuptools.dynamic.version]
44
+ attr = 'spin.__version__'
45
+
43
46
  [tool.setuptools.packages.find]
44
47
  include = ["spin*"]
45
48
 
@@ -50,7 +53,7 @@ filterwarnings = [
50
53
 
51
54
  [tool.ruff]
52
55
  line-length = 88
53
- target-version = "py37"
56
+ target-version = "py38"
54
57
  select = [
55
58
  "C",
56
59
  "E",
@@ -6,6 +6,8 @@ For usage information see `python -m spin`.
6
6
  Read more at https://github.com/scientific-python/spin
7
7
  """
8
8
 
9
+ __version__ = "0.9"
10
+
9
11
  from .cmds import util
10
12
 
11
13
  __all__ = ["util"]
@@ -1,3 +1,4 @@
1
+ import collections
1
2
  import importlib
2
3
  import importlib.util
3
4
  import os
@@ -5,6 +6,7 @@ import sys
5
6
 
6
7
  import click
7
8
 
9
+ from spin import __version__
8
10
  from spin import cmds as _cmds
9
11
  from spin.color_format import ColorHelpFormatter
10
12
  from spin.containers import DotDict
@@ -19,35 +21,64 @@ click.Context.formatter_class = ColorHelpFormatter
19
21
 
20
22
 
21
23
  def main():
22
- if not os.path.exists("pyproject.toml"):
23
- print("Error: cannot find [pyproject.toml]")
24
- sys.exit(1)
25
-
26
- with open("pyproject.toml", "rb") as f:
27
- try:
28
- toml_config = tomllib.load(f)
29
- except tomllib.TOMLDecodeError:
30
- print("Cannot parse [pyproject.toml]")
31
- sys.exit(1)
32
-
33
- project_config = toml_config.get("project", {})
34
-
35
- try:
36
- config = toml_config["tool"]["spin"]
37
- except KeyError:
38
- print("No configuration found in [pyproject.toml] for [tool.spin]")
39
- sys.exit(1)
40
-
41
- proj_name = project_config.get("name", config["package"])
24
+ # Alias `spin help` to `spin --help`
25
+ if (len(sys.argv) == 2) and (sys.argv[1] == "help"):
26
+ sys.argv[1] = "--help"
27
+
28
+ def load_toml(filename):
29
+ if not os.path.exists(filename):
30
+ return None
31
+ with open(filename, "rb") as f:
32
+ try:
33
+ return tomllib.load(f)
34
+ except tomllib.TOMLDecodeError:
35
+ print(f"Error: cannot parse [{filename}]", file=sys.stderr)
36
+
37
+ toml_config = collections.ChainMap()
38
+ toml_config.maps.extend(
39
+ DotDict(cfg)
40
+ for filename in (
41
+ ".spin.toml",
42
+ "spin.toml",
43
+ "pyproject.toml",
44
+ )
45
+ if (cfg := load_toml(filename))
46
+ )
47
+
48
+ # Basic configuration validation
49
+ version_query = len(sys.argv) == 2 and (sys.argv[1] == "--version")
50
+
51
+ spin_config = {}
52
+ if not version_query:
53
+ if "tool.spin" in toml_config:
54
+ spin_config = toml_config["tool.spin"]
55
+ if "tool.spin.commands" not in toml_config:
56
+ print(
57
+ "Error: configuration is missing section [tool.spin.commands]\n",
58
+ file=sys.stderr,
59
+ )
60
+ else:
61
+ print(
62
+ "Error: need valid configuration in [.spin.toml], [spin.toml], or [pyproject.toml]\n"
63
+ "See https://github.com/scientific-python/spin/blob/main/README.md\n",
64
+ file=sys.stderr,
65
+ )
66
+
67
+ proj_name = (
68
+ toml_config.get("project.name")
69
+ or spin_config.get("package")
70
+ or "[unknown project]"
71
+ )
42
72
 
43
73
  @click.group(help=f"Developer tool for {proj_name}", cls=SectionedHelpGroup)
74
+ @click.version_option(__version__, message="%(prog)s %(version)s")
44
75
  @click.pass_context
45
76
  def group(ctx):
46
- ctx.meta["config"] = DotDict(toml_config)
77
+ ctx.meta["config"] = toml_config
47
78
  ctx.meta["commands"] = ctx.command.section_commands
48
79
  ctx.show_default = True
49
80
 
50
- config_cmds = config["commands"]
81
+ config_cmds = spin_config.get("commands", [])
51
82
  # Commands can be provided as a list, or as a dictionary
52
83
  # so that they can be sorted into sections
53
84
  if isinstance(config_cmds, list):
@@ -63,6 +94,7 @@ def main():
63
94
  "spin.python": _cmds.meson.python,
64
95
  "spin.shell": _cmds.meson.shell,
65
96
  }
97
+ cmd_default_kwargs = toml_config.get("tool.spin.kwargs", {})
66
98
 
67
99
  for section, cmds in config_cmds.items():
68
100
  for cmd in cmds:
@@ -102,6 +134,18 @@ def main():
102
134
  print(f"!! Could not load command `{func}` from file `{path}`.\n")
103
135
  continue
104
136
 
137
+ default_kwargs = cmd_default_kwargs.get(cmd)
138
+ import functools
139
+
140
+ if default_kwargs:
141
+ callback = cmd_func.callback
142
+ cmd_func.callback = functools.partial(callback, **default_kwargs)
143
+
144
+ # Also override option defaults
145
+ for option in cmd_func.params:
146
+ if option.name in default_kwargs:
147
+ option.default = default_kwargs[option.name]
148
+
105
149
  commands[cmd] = cmd_func
106
150
 
107
151
  group.add_command(commands[cmd], section=section)
@@ -109,7 +153,7 @@ def main():
109
153
  try:
110
154
  group()
111
155
  except Exception as e:
112
- print(f"{e}; aborting.")
156
+ print(f"Error: {e}; aborting.", file=sys.stderr)
113
157
  sys.exit(1)
114
158
 
115
159
 
@@ -6,4 +6,4 @@ from .util import run
6
6
  @click.command()
7
7
  def sdist():
8
8
  """📦 Build a source distribution in `dist/`"""
9
- run(["python", "-m", "build", ".", "--sdist"])
9
+ run(["pyproject-build", ".", "--sdist"])