spin 0.8__tar.gz → 0.10__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.8
3
+ Version: 0.10
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
@@ -53,24 +53,28 @@ License-File: LICENSE
53
53
  Requires-Dist: click
54
54
  Requires-Dist: tomli; python_version < "3.11"
55
55
  Requires-Dist: colorama; platform_system == "Windows"
56
+ Requires-Dist: importlib_metadata>=7
56
57
  Provides-Extra: lint
57
- Requires-Dist: pre-commit==3.5.0; extra == "lint"
58
+ Requires-Dist: pre-commit==3.7.0; extra == "lint"
58
59
  Provides-Extra: dev
59
- Requires-Dist: changelist==0.4; extra == "dev"
60
+ Requires-Dist: changelist==0.5; extra == "dev"
60
61
 
61
62
  # 💫 Scientific Python INcantations (`spin`)
62
63
 
63
64
  ## A developer tool for scientific Python libraries
64
65
 
65
66
  Developers need to memorize a whole bunch of magic command-line incantations.
66
- And these incantations change from time to time!
67
- Typically, their lives are made simpler by a Makefile, but Makefiles can be convoluted, are not written in Python, and are hard to extend.
68
- 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.
69
70
  It comes with a few common build commands out the box, but can easily be customized per project.
70
71
 
71
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.
72
73
  When many of the build and installation commands changed, it made sense to abstract away the nuisance of having to re-learn them.
73
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
+
74
78
  ## Installation
75
79
 
76
80
  ```
@@ -116,7 +120,7 @@ These commands will then be rendered as:
116
120
 
117
121
  ```
118
122
  Build:
119
- build 🔧 Build package with Meson/ninja and install
123
+ build 🔧 Build package with Meson/ninja
120
124
  test 🔧 Run tests
121
125
 
122
126
  Environments:
@@ -143,7 +147,7 @@ python -m spin
143
147
  Available as `spin.cmds.meson.*`.
144
148
 
145
149
  ```
146
- build 🔧 Build package with Meson/ninja and install to `build-install`
150
+ build 🔧 Build package with Meson/ninja
147
151
  ipython 💻 Launch IPython shell with PYTHONPATH set
148
152
  python 🐍 Launch Python shell with PYTHONPATH set
149
153
  shell 💻 Launch shell with PYTHONPATH set
@@ -152,7 +156,6 @@ Available as `spin.cmds.meson.*`.
152
156
  docs 📖 Build Sphinx documentation
153
157
  gdb 👾 Execute a Python snippet with GDB
154
158
  lldb 👾 Execute a Python snippet with LLDB
155
- install 💽 Build and install package using pip.
156
159
  ```
157
160
 
158
161
  ### [Build](https://pypa-build.readthedocs.io/en/stable/) (PEP 517 builder)
@@ -168,9 +171,6 @@ Available as `spin.cmds.build.*`:
168
171
  `pip` allows for editable installs, another common
169
172
  development workflow.
170
173
 
171
- Note that, for now, the meson commands above do not work with an
172
- editable install of the package. We're [working on changing that](https://github.com/scientific-python/spin/pull/141).
173
-
174
174
  Available as `spin.cmds.pip.*`:
175
175
 
176
176
  ```
@@ -207,6 +207,29 @@ def example():
207
207
  print(config["tool.spin"])
208
208
  ```
209
209
 
210
+ ### Argument overrides
211
+
212
+ Default arguments can be overridden for any command.
213
+ The custom command above, e.g., has the following signature:
214
+
215
+ ```python
216
+ @click.command()
217
+ @click.option("-f", "--flag")
218
+ @click.option("-t", "--test", default="not set")
219
+ def example(flag, test, default_kwd=None):
220
+ """🧪 Example custom command.
221
+ ...
222
+ """
223
+ ```
224
+
225
+ Use the `[tool.spin.kwargs]` section to override default values for
226
+ click options or function keywords:
227
+
228
+ ```toml
229
+ [tool.spin.kwargs]
230
+ ".spin/cmds.py:example" = {"test" = "default override", "default_kwd" = 3}
231
+ ```
232
+
210
233
  ### Advanced: adding arguments to built-in commands
211
234
 
212
235
  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.
@@ -284,7 +307,7 @@ fc-cache -f -v
284
307
  `spin` tests are invoked using:
285
308
 
286
309
  ```
287
- nox -s tests
310
+ nox -s test
288
311
  ```
289
312
 
290
313
  ## History
@@ -3,14 +3,17 @@
3
3
  ## A developer tool for scientific Python libraries
4
4
 
5
5
  Developers need to memorize a whole bunch of magic command-line incantations.
6
- And these incantations change from time to time!
7
- Typically, their lives are made simpler by a Makefile, but Makefiles can be convoluted, are not written in Python, and are hard to extend.
8
- 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.
9
9
  It comes with a few common build commands out the box, but can easily be customized per project.
10
10
 
11
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.
12
12
  When many of the build and installation commands changed, it made sense to abstract away the nuisance of having to re-learn them.
13
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
+
14
17
  ## Installation
15
18
 
16
19
  ```
@@ -56,7 +59,7 @@ These commands will then be rendered as:
56
59
 
57
60
  ```
58
61
  Build:
59
- build 🔧 Build package with Meson/ninja and install
62
+ build 🔧 Build package with Meson/ninja
60
63
  test 🔧 Run tests
61
64
 
62
65
  Environments:
@@ -83,7 +86,7 @@ python -m spin
83
86
  Available as `spin.cmds.meson.*`.
84
87
 
85
88
  ```
86
- build 🔧 Build package with Meson/ninja and install to `build-install`
89
+ build 🔧 Build package with Meson/ninja
87
90
  ipython 💻 Launch IPython shell with PYTHONPATH set
88
91
  python 🐍 Launch Python shell with PYTHONPATH set
89
92
  shell 💻 Launch shell with PYTHONPATH set
@@ -92,7 +95,6 @@ Available as `spin.cmds.meson.*`.
92
95
  docs 📖 Build Sphinx documentation
93
96
  gdb 👾 Execute a Python snippet with GDB
94
97
  lldb 👾 Execute a Python snippet with LLDB
95
- install 💽 Build and install package using pip.
96
98
  ```
97
99
 
98
100
  ### [Build](https://pypa-build.readthedocs.io/en/stable/) (PEP 517 builder)
@@ -108,9 +110,6 @@ Available as `spin.cmds.build.*`:
108
110
  `pip` allows for editable installs, another common
109
111
  development workflow.
110
112
 
111
- Note that, for now, the meson commands above do not work with an
112
- editable install of the package. We're [working on changing that](https://github.com/scientific-python/spin/pull/141).
113
-
114
113
  Available as `spin.cmds.pip.*`:
115
114
 
116
115
  ```
@@ -147,6 +146,29 @@ def example():
147
146
  print(config["tool.spin"])
148
147
  ```
149
148
 
149
+ ### Argument overrides
150
+
151
+ Default arguments can be overridden for any command.
152
+ The custom command above, e.g., has the following signature:
153
+
154
+ ```python
155
+ @click.command()
156
+ @click.option("-f", "--flag")
157
+ @click.option("-t", "--test", default="not set")
158
+ def example(flag, test, default_kwd=None):
159
+ """🧪 Example custom command.
160
+ ...
161
+ """
162
+ ```
163
+
164
+ Use the `[tool.spin.kwargs]` section to override default values for
165
+ click options or function keywords:
166
+
167
+ ```toml
168
+ [tool.spin.kwargs]
169
+ ".spin/cmds.py:example" = {"test" = "default override", "default_kwd" = 3}
170
+ ```
171
+
150
172
  ### Advanced: adding arguments to built-in commands
151
173
 
152
174
  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.
@@ -224,7 +246,7 @@ fc-cache -f -v
224
246
  `spin` tests are invoked using:
225
247
 
226
248
  ```
227
- nox -s tests
249
+ nox -s test
228
250
  ```
229
251
 
230
252
  ## History
@@ -25,7 +25,8 @@ classifiers = [
25
25
  dependencies = [
26
26
  "click",
27
27
  "tomli; python_version < '3.11'",
28
- "colorama; platform_system == 'Windows'"
28
+ "colorama; platform_system == 'Windows'",
29
+ "importlib_metadata >= 7"
29
30
  ]
30
31
  dynamic = ['version']
31
32
 
@@ -33,8 +34,8 @@ dynamic = ['version']
33
34
  spin = "spin.__main__:main"
34
35
 
35
36
  [project.optional-dependencies]
36
- lint = ["pre-commit == 3.5.0"]
37
- dev = ["changelist == 0.4"]
37
+ lint = ["pre-commit == 3.7.0"]
38
+ dev = ["changelist == 0.5"]
38
39
 
39
40
  [project.urls]
40
41
  homepage = "https://github.com/scientific-python/spin"
@@ -53,6 +54,8 @@ filterwarnings = [
53
54
  [tool.ruff]
54
55
  line-length = 88
55
56
  target-version = "py38"
57
+
58
+ [tool.ruff.lint]
56
59
  select = [
57
60
  "C",
58
61
  "E",
@@ -6,7 +6,7 @@ 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.8"
9
+ __version__ = "0.10"
10
10
 
11
11
  from .cmds import util
12
12
 
@@ -3,6 +3,8 @@ import importlib
3
3
  import importlib.util
4
4
  import os
5
5
  import sys
6
+ import textwrap
7
+ import traceback
6
8
 
7
9
  import click
8
10
 
@@ -25,10 +27,6 @@ def main():
25
27
  if (len(sys.argv) == 2) and (sys.argv[1] == "help"):
26
28
  sys.argv[1] = "--help"
27
29
 
28
- def error(message):
29
- print(f"Error: {message}", file=sys.stderr)
30
- sys.exit(1)
31
-
32
30
  def load_toml(filename):
33
31
  if not os.path.exists(filename):
34
32
  return None
@@ -36,7 +34,7 @@ def main():
36
34
  try:
37
35
  return tomllib.load(f)
38
36
  except tomllib.TOMLDecodeError:
39
- error("cannot parse [{filename}]")
37
+ print(f"Error: cannot parse [{filename}]", file=sys.stderr)
40
38
 
41
39
  toml_config = collections.ChainMap()
42
40
  toml_config.maps.extend(
@@ -50,18 +48,28 @@ def main():
50
48
  )
51
49
 
52
50
  # Basic configuration validation
53
- if "tool.spin" not in toml_config:
54
- error(
55
- "needs valid configuration in [.spin.toml], [spin.toml] or [pyproject.toml]"
56
- )
57
- if "tool.spin.commands" not in toml_config:
58
- error("configuration is missing section [tool.spin.commands]")
51
+ version_query = len(sys.argv) == 2 and (sys.argv[1] == "--version")
52
+
53
+ spin_config = {}
54
+ if not version_query:
55
+ if "tool.spin" in toml_config:
56
+ spin_config = toml_config["tool.spin"]
57
+ if "tool.spin.commands" not in toml_config:
58
+ print(
59
+ "Error: configuration is missing section [tool.spin.commands]\n",
60
+ file=sys.stderr,
61
+ )
62
+ else:
63
+ print(
64
+ "Error: need valid configuration in [.spin.toml], [spin.toml], or [pyproject.toml]\n"
65
+ "See https://github.com/scientific-python/spin/blob/main/README.md\n",
66
+ file=sys.stderr,
67
+ )
59
68
 
60
- spin_config = toml_config["tool.spin"]
61
69
  proj_name = (
62
70
  toml_config.get("project.name")
63
71
  or spin_config.get("package")
64
- or "unknown project"
72
+ or "[unknown project]"
65
73
  )
66
74
 
67
75
  @click.group(help=f"Developer tool for {proj_name}", cls=SectionedHelpGroup)
@@ -72,7 +80,7 @@ def main():
72
80
  ctx.meta["commands"] = ctx.command.section_commands
73
81
  ctx.show_default = True
74
82
 
75
- config_cmds = spin_config["commands"]
83
+ config_cmds = spin_config.get("commands", [])
76
84
  # Commands can be provided as a list, or as a dictionary
77
85
  # so that they can be sorted into sections
78
86
  if isinstance(config_cmds, list):
@@ -88,6 +96,7 @@ def main():
88
96
  "spin.python": _cmds.meson.python,
89
97
  "spin.shell": _cmds.meson.shell,
90
98
  }
99
+ cmd_default_kwargs = toml_config.get("tool.spin.kwargs", {})
91
100
 
92
101
  for section, cmds in config_cmds.items():
93
102
  for cmd in cmds:
@@ -127,14 +136,44 @@ def main():
127
136
  print(f"!! Could not load command `{func}` from file `{path}`.\n")
128
137
  continue
129
138
 
139
+ default_kwargs = cmd_default_kwargs.get(cmd)
140
+ import functools
141
+
142
+ if default_kwargs:
143
+ callback = cmd_func.callback
144
+ cmd_func.callback = functools.partial(callback, **default_kwargs)
145
+
146
+ # Also override option defaults
147
+ for option in cmd_func.params:
148
+ if option.name in default_kwargs:
149
+ option.default = default_kwargs[option.name]
150
+
130
151
  commands[cmd] = cmd_func
131
152
 
132
153
  group.add_command(commands[cmd], section=section)
133
154
 
134
155
  try:
135
156
  group()
136
- except Exception as e:
137
- error(f"{e}; aborting.")
157
+ except Exception:
158
+ click.secho("\n" + traceback.format_exc(limit=-3), fg="red", file=sys.stderr)
159
+ click.secho(
160
+ textwrap.dedent(
161
+ f"""\
162
+ An internal error has occurred. Please file a bug report at
163
+
164
+ https://github.com/scientific-python/spin
165
+
166
+ including the above traceback and the following information:
167
+
168
+ spin: {__version__}, package: {proj_name}
169
+
170
+ Aborting."""
171
+ ),
172
+ fg="red",
173
+ bold=True,
174
+ file=sys.stderr,
175
+ )
176
+ sys.exit(1)
138
177
 
139
178
 
140
179
  if __name__ == "__main__":