Skip to content

Commit 462e34d

Browse files
authored
Add extra-arguments for Conan CLI overrides in pyproject.toml (#47)
* add extra-arguments * wip * bump version
1 parent 833ac36 commit 462e34d

4 files changed

Lines changed: 107 additions & 1 deletion

File tree

docs/configuration.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ All project-level options live under
2020
|--------|--------------|-------------|---------|
2121
| `conanfile-path` | `[tool.conan-py-build]` | Path to the Conan recipe, relative to project root | `"."` |
2222
| `extra-profile` | `[tool.conan-py-build]` | Extra Conan profile composed on top of the active one | (none) |
23+
| `extra-arguments` | `[tool.conan-py-build]` | Extra Conan CLI flags appended to `conan build` and `conan export-pkg` | `[]` |
2324
| `version.file` | `[tool.conan-py-build.version]` | Python file with `__version__` | (none) |
2425
| `version.provider` | `[tool.conan-py-build.version]` | `"setuptools_scm"` for version from git tags | (none) |
2526
| `packages` | `[tool.conan-py-build.wheel]` | Paths to Python packages in the wheel | `["src/<name>"]` |
@@ -29,6 +30,10 @@ Variants for extra profiles: `extra-profile-host`,
2930
`extra-profile-build`, `extra-profile-all`.
3031
Paths relative to project root.
3132

33+
For one-off Conan overrides without shipping a separate
34+
profile file, use `extra-arguments` (see *Extra Conan
35+
arguments* below).
36+
3237
Default `packages` is `src/<normalized_project_name>`
3338
(hyphens → underscores).
3439

@@ -119,6 +124,47 @@ or `CONAN_HOME` / `.conanrc`). Set
119124
`CONAN_PY_BUILD_PROFILE_AUTODETECT=1` to autodetect
120125
the profile instead of requiring `default`.
121126

127+
## Extra Conan arguments
128+
129+
CLI flags appended to `conan build` and
130+
`conan export-pkg`. Symmetric with `extra-profile`,
131+
with higher precedence — CLI flags win against any
132+
profile entry.
133+
134+
Bump `compiler.cppstd` to match a transitive dep
135+
(e.g. `gdal/3.12.1` requires C++17, MSVC defaults
136+
to 14):
137+
138+
```toml
139+
[tool.conan-py-build]
140+
extra-arguments = ["-s=compiler.cppstd=17"]
141+
```
142+
143+
Disable an optional dep feature and pin parallelism:
144+
145+
```toml
146+
[tool.conan-py-build]
147+
extra-arguments = [
148+
"-o=gdal/*:with_arrow=False",
149+
"-c=tools.build:jobs=4",
150+
]
151+
```
152+
153+
For values with embedded double quotes (dict / list
154+
`[conf]` literals), use TOML literal strings (`'...'`):
155+
156+
```toml
157+
extra-arguments = [
158+
'-c=tools.build:cflags+=["-O2", "-fPIC"]',
159+
'-c=tools.cmake.cmaketoolchain:extra_variables={"FOO": "bar"}',
160+
]
161+
```
162+
163+
Any Conan CLI flag works: `-s` / `-o` / `-c` (host),
164+
`-s:b` / `-o:b` / `-c:b` (build context),
165+
`--build=...`, `--lockfile=...`. Pair-form
166+
(`["-s", "compiler.cppstd=17"]`) is also accepted.
167+
122168
## Entry points (PEP 621)
123169

124170
`[project.scripts]`, `[project.gui-scripts]` and

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "conan-py-build"
7-
version = "0.4.2"
7+
version = "0.4.3"
88
description = "A minimal PEP 517 compliant build backend that uses Conan to build Python C/C++ extensions"
99
readme = "README.md"
1010
license = {text = "MIT"}

src/conan_py_build/build.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,23 @@ def _autodetect_profile() -> bool:
225225
return env_val in ("1", "true", "yes")
226226

227227

228+
def _extra_arguments(tool_cfg: dict) -> List[str]:
229+
"""Return ``[tool.conan-py-build].extra-arguments`` validated as ``list[str]``.
230+
231+
Appended verbatim to ``conan build`` and ``conan export-pkg`` invocations,
232+
symmetric with ``extra-profile``. Typical uses: ``-s`` / ``-o`` / ``-c``
233+
overrides, ``--lockfile``, ``--build=...``, per-context ``-s:b`` flags.
234+
"""
235+
args = tool_cfg.get("extra-arguments")
236+
if args is None:
237+
return []
238+
if not isinstance(args, list) or not all(isinstance(a, str) for a in args):
239+
raise RuntimeError(
240+
"[tool.conan-py-build].extra-arguments must be a list of strings."
241+
)
242+
return args
243+
244+
228245
def _resolve_default_profiles(conan_api, source_dir: Path, host_profile: str, build_profile: str) -> Tuple[str, str]:
229246
if host_profile != "default" and build_profile != "default":
230247
return host_profile, build_profile
@@ -525,6 +542,8 @@ def _do_build_wheel(
525542
arg = key[len("extra-"):].replace("-", ":", 1) # profile-host -> profile:host
526543
profile_args.extend([f"--{arg}", str(p)])
527544

545+
extra_args = _extra_arguments(tool)
546+
528547
conanfile_path = tool.get("conanfile-path") or "."
529548
resolved_conanfile = str(_resolve_conanfile_path(conanfile_path, source_dir))
530549

@@ -549,6 +568,7 @@ def _do_build_wheel(
549568
"--build=missing",
550569
]
551570
build_cmd.extend(profile_args)
571+
build_cmd.extend(extra_args)
552572

553573
print(
554574
f"Running conan build (profiles: host={host_profile}, build={build_profile})...",
@@ -580,6 +600,7 @@ def _do_build_wheel(
580600
user_presets_conf,
581601
]
582602
export_pkg_cmd.extend(profile_args)
603+
export_pkg_cmd.extend(extra_args)
583604
try:
584605
export_result = conan_api.command.run(export_pkg_cmd)
585606
except Exception as e:

tests/test_unit.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
_get_wheel_packages,
2222
_create_dist_info,
2323
_write_entry_points,
24+
_extra_arguments,
2425
_build_wheel_with_tags,
2526
_copy_license_files_from_paths,
2627
_validate_version_config,
@@ -157,6 +158,44 @@ def test_move_deploy_to_wheel_copies_shared_libs_next_to_extension(tmp_path):
157158
assert (pkg / "libdep.so").read_text() == "so"
158159

159160

161+
def test_extra_arguments_empty_when_unset():
162+
assert _extra_arguments({}) == []
163+
assert _extra_arguments({"extra-arguments": []}) == []
164+
165+
166+
def test_extra_arguments_returns_list_verbatim():
167+
args = ["-s=compiler.cppstd=17", "-o=gdal/*:shared=True", "-c=tools.build:jobs=4"]
168+
assert _extra_arguments({"extra-arguments": args}) == args
169+
170+
171+
def test_extra_arguments_supports_pair_form():
172+
"""Pair-form ``["-s", "value"]`` is passed through unchanged — argparse
173+
accepts both ``-s value`` and ``-s=value`` on Conan's CLI."""
174+
args = ["-s", "compiler.cppstd=17", "-o", "gdal/*:shared=True", "-c", "tools.build:jobs=4"]
175+
assert _extra_arguments({"extra-arguments": args}) == args
176+
177+
178+
def test_extra_arguments_supports_mixed_pair_and_equals_form():
179+
"""Mixing equals-form and pair-form in the same list works — argparse
180+
processes each token independently."""
181+
args = [
182+
"-s=compiler.cppstd=17",
183+
"-o", "gdal/*:shared=True",
184+
"-c=tools.build:jobs=4",
185+
]
186+
assert _extra_arguments({"extra-arguments": args}) == args
187+
188+
189+
def test_extra_arguments_rejects_non_list():
190+
with pytest.raises(RuntimeError, match="must be a list of strings"):
191+
_extra_arguments({"extra-arguments": "-s=compiler.cppstd=17"})
192+
193+
194+
def test_extra_arguments_rejects_non_string_items():
195+
with pytest.raises(RuntimeError, match="must be a list of strings"):
196+
_extra_arguments({"extra-arguments": ["-s", {"k": "v"}]})
197+
198+
160199
def test_get_sdist_config_minimal_pyproject(tmp_path):
161200
make_pyproject_minimal(tmp_path)
162201
assert _get_sdist_config(tmp_path) == {"include": [], "exclude": []}

0 commit comments

Comments
 (0)