Skip to content

Commit b75b2a4

Browse files
authored
Merge pull request #205 from davidhewitt/kebab-case-executables
exec: support kebab-case executables
2 parents 295bc84 + da2bdd7 commit b75b2a4

File tree

4 files changed

+38
-10
lines changed

4 files changed

+38
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Unreleased
4+
### Added
5+
- Add support for `kebab-case` executable names. [#205](https://github.com/PyO3/setuptools-rust/pull/205)
6+
37
## 1.1.2 (2021-12-05)
48
### Changed
59
- Removed dependency on `tomli` to simplify installation. [#200](https://github.com/PyO3/setuptools-rust/pull/200)

examples/hello-world/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
version="1.0",
88
rust_extensions=[
99
RustExtension(
10-
{"hello-world": "hello_world.hello_world"},
10+
{"hello-world": "hello_world.hello-world"},
1111
binding=Binding.Exec,
1212
script=True,
1313
)

examples/hello-world/tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ requires =
66
description = Run the unit tests under {basepython}
77
deps =
88
setuptools-rust @ file://{toxinidir}/../../
9-
commands = hello_world {posargs}
9+
commands = hello-world {posargs}
1010
passenv = *

setuptools_rust/extension.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ class RustExtension:
5858
packages, i.e *not* a filename or pathname. It is possible to
5959
specify multiple binaries, if extension uses ``Binding.Exec``
6060
binding mode. In that case first argument has to be dictionary.
61-
Keys of the dictionary corresponds to compiled rust binaries and
62-
values are full name of the executable inside python package.
61+
Keys of the dictionary correspond to the rust binary names and
62+
values are the full dotted name to place the executable inside
63+
the python package. To install executables with kebab-case names,
64+
the final part of the dotted name can be in kebab-case. For
65+
example, `hello_world.hello-world` will install an executable
66+
named `hello-world`.
6367
path: Path to the ``Cargo.toml`` manifest file.
64-
args: A list of extra argumenents to be passed to Cargo. For example,
68+
args: A list of extra arguments to be passed to Cargo. For example,
6569
``args=["--no-default-features"]`` will disable the default
6670
features listed in ``Cargo.toml``.
6771
features: A list of Cargo features to also build.
@@ -169,19 +173,20 @@ def get_rust_version(self) -> Optional[SimpleSpec]: # type: ignore[no-any-unimp
169173
def entry_points(self) -> List[str]:
170174
entry_points = []
171175
if self.script and self.binding == Binding.Exec:
172-
for name, mod in self.target.items():
176+
for executable, mod in self.target.items():
173177
base_mod, name = mod.rsplit(".")
174-
script = "%s=%s.%s:run" % (name, base_mod, "_gen_%s" % name)
178+
script = "%s=%s.%s:run" % (name, base_mod, _script_name(executable))
175179
entry_points.append(script)
176180

177181
return entry_points
178182

179183
def install_script(self, module_name: str, exe_path: str) -> None:
180184
if self.script and self.binding == Binding.Exec:
181185
dirname, executable = os.path.split(exe_path)
182-
file = os.path.join(dirname, "_gen_%s.py" % module_name)
186+
script_name = _script_name(module_name)
187+
file = os.path.join(dirname, f"{script_name}.py")
183188
with open(file, "w") as f:
184-
f.write(_TMPL.format(executable=repr(executable)))
189+
f.write(_SCRIPT_TEMPLATE.format(executable=repr(executable)))
185190

186191
def _metadata(self) -> "_CargoMetadata":
187192
"""Returns cargo metedata for this extension package.
@@ -207,7 +212,26 @@ def _uses_exec_binding(self) -> bool:
207212
_CargoMetadata = NewType("_CargoMetadata", Dict[str, Any])
208213

209214

210-
_TMPL = """
215+
def _script_name(executable: str) -> str:
216+
"""Generates the name of the installed Python script for an executable.
217+
218+
Because Python modules must be snake_case, this generated script name will
219+
replace `-` with `_`.
220+
221+
>>> _script_name("hello-world")
222+
'_gen_hello_world'
223+
224+
>>> _script_name("foo_bar")
225+
'_gen_foo_bar'
226+
227+
>>> _script_name("_gen_foo_bar")
228+
'_gen__gen_foo_bar'
229+
"""
230+
script = executable.replace("-", "_")
231+
return f"_gen_{script}"
232+
233+
234+
_SCRIPT_TEMPLATE = """
211235
import os
212236
import sys
213237

0 commit comments

Comments
 (0)