Mysterious error in source.convert when using tomlkit instead of tomlib
MementoRC opened this issue · 2 comments
tomlib
is not available in early version of python. I used tomlkit
instead to read a supplemental scikit_config to modify the settings
prior to calling the BUilder to experiment with buildiing TARGETS and installing associated COMPONENTS. But I encounter a very incomprehensible issue where the dictionary created by tomlkit
(in fact a TOMLDocument) create this fail:
xxx/.conda/envs/python-3.11/lib/python3.11/typing.py", line 462, in __call__
E | raise TypeError(f"Cannot instantiate {self!r}")
E | TypeError: Cannot instantiate typing.Union
E | Field tool.scikit-build.cmake.define
E +------------------------------------
It occurs in:
if raw_target is Union and type(item) in get_args(target):
return item
if raw_target is Literal:
if item not in get_args(_process_union(target)):
msg = f"{item!r} not in {get_args(_process_union(target))!r}"
raise TypeError(msg)
return item
if callable(raw_target):
return raw_target(item) # <-
But it should be routed to if raw_target is Union and type(item) in get_args(target):
In my code, I tried trahsferring the TOMLDocument to a simple dict and assert that both tomlkit
and tomlib
dictionary are the same, but the tomlib
is passing while the tomlkit
fails
This is the updating function (butchered from desperation at understanding this issue):
def update_scikit_config_from_plugin(root_dir: str, config: dict[str, Any]) -> dict[str, Any]:
"""
Reads scikit-build-core TOML configuration from its configuration file
defined in the plugin configuration 'toml-file' entry.
Updates scikit-build-core TOML configuration based upon entries of
the plugin configuration.
Note: The 'targets' entry of the plugin configuration must NOT be passed
to the configuration phase of CMake/Builder
:param root_dir: Root directory of the project
:param config: Plugin configuration (TOML)
:return: Updated configuration
"""
def _get_TOML_scikit_config(path) -> dict[str, Any]:
toml: TOMLDocument = TOMLFile(path).read().get('tool', {}).setdefault('scikit-build', {})
return {k: v for k, v in toml.items()}
def _update_config_defaults(sk_config: dict[str, Any]) -> dict[str, Any]:
# Retrieve the configuration entries from the plugin configuration
sdist: dict[str, Any] = sk_config.setdefault('sdist', {})
wheel: dict[str, Any] = sk_config.setdefault('wheel', {})
# We disable sdist ('sdist' build should be ignored by the hook initialization)
if sdist.get('cmake', False):
log.warning("scikit hatch plugin disables the 'cmake' option in the 'sdist' section")
sdist['cmake'] = False
sdist['include'] = []
# Override the eventual 'packages' in the scikit-build-core config (these should be handled by hatchling)
if wheel.get('packages', False):
log.warning('scikit hatch plugin resets the wheel packages to an empty list')
# wheel['cmake'] = True
wheel['packages'] = []
wheel['platlib'] = 'platlib'
return sk_config
# Typically, the scikit-build-core configuration is stored in the 'pyproject.toml' file
tomlfile_for_scikit: str = config.get('toml-file', 'pyproject.toml')
if not (toml_file_path := Path(os.path.join(root_dir, tomlfile_for_scikit))).exists():
msg = f'Could not find {tomlfile_for_scikit} in the project root directory'
raise FileNotFoundError(msg)
# Read settings from the tool.scikit-build section of the pyproject.toml
scikit_config: dict[str, Any] = _get_TOML_scikit_config(toml_file_path)
with toml_file_path.open('rb') as ft:
import tomllib
scikit_config0: dict[str, Any] = (tomllib.load(ft)).get('tool', {}).setdefault('scikit-build', {})
assert scikit_config == scikit_config0
# Entries are dependent upon scikit-build-core API (current v0.8.2)
scikit_config0 = _update_config_defaults(scikit_config0)
scikit_config = _update_config_defaults(scikit_config)
assert scikit_config == scikit_config0
# Update the scikit-build-core directories (the default setting works well with hatchling)
#if (_res := 'source-dir') and (_dir := config.get(_res, None)):
# scikit_config.setdefault('cmake', {})[_res] = _dir
# scikit_config0.setdefault('cmake', {})[_res] = _dir
print(f"scikit_config: {((scikit_config))}")
print(f"scikit_config: {(scikit_config0)}")
assert scikit_config == scikit_config0
return {'tool': {'scikit-build': scikit_config}}
Tomli is the backport of tomllib. Does that work? I can still check to see why tomlkit is failing; but that makes special versions of dicts and things so it can 100% round trip and that might trip us up.
you only need tomlkit when writing a document that you read back out.
Great, that works, thanks. Closing the issue