When a source schema has slots with no explicit range (i.e., range=None), _map_value_by_range recurses into map_object with None as the source type. For scalar values (strings, ints, etc.), map_object then hits the not isinstance(source_obj, dict) check and logs a warning:
WARNING Unexpected: <value> for type None
This happens for every scalar field without an explicit range, producing many spurious warnings during normal transforms.
Root Cause
In _map_value_by_range (object_transformer.py), when source_class_slot.range is None and there are no any_of enums, the method falls through to the recursive map_object call at line 611. For scalar values, map_object receives source_type=None, which isn't in all_types() or all_enums(), the value isn't a dict, so it logs the warning and returns the value unchanged.
The recursion is pointless for scalars when there's no range — there's nothing to map.
Reproducer
from linkml_map.transformer.object_transformer import ObjectTransformer
from linkml_runtime.utils.schemaview import SchemaView
import yaml
import tempfile
import logging
logging.basicConfig(level=logging.DEBUG)
def write_temp(content):
f = tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False)
f.write(content) if isinstance(content, str) else yaml.dump(content, f)
f.close()
return f.name
# Schema where slots have no explicit range (inherits default_range or None)
source_schema = """
id: https://example.org/source
name: source
prefixes:
linkml: https://w3id.org/linkml/
imports:
- linkml:types
classes:
Record:
attributes:
record_id:
identifier: true
title:
description:
"""
target_schema = """
id: https://example.org/target
name: target
prefixes:
linkml: https://w3id.org/linkml/
imports:
- linkml:types
default_range: string
classes:
Output:
attributes:
id:
name:
description:
"""
transform = {
"id": "test",
"class_derivations": {
"Output": {
"populated_from": "Record",
"slot_derivations": {
"id": {"populated_from": "record_id"},
"name": {"populated_from": "title"},
"description": {"populated_from": "description"},
},
}
},
}
src_path = write_temp(source_schema)
tgt_path = write_temp(target_schema)
transform["source_schema"] = src_path
transform["target_schema"] = tgt_path
tr_path = write_temp(transform)
tr = ObjectTransformer(unrestricted_eval=True)
tr.source_schemaview = SchemaView(src_path)
tr.load_transformer_specification(tr_path)
input_obj = {"record_id": "rec-001", "title": "Hello", "description": "A test record"}
tr.index(input_obj, "Record")
result = tr.map_object(input_obj, "Record")
# Produces 3 "Unexpected" warnings, one per field
Fix
In _map_value_by_range, when range is None/"Any" and there are no any_of enums, return scalar values directly instead of recursing:
if not isinstance(v, (dict, list)):
return v
When a source schema has slots with no explicit
range(i.e.,range=None),_map_value_by_rangerecurses intomap_objectwithNoneas the source type. For scalar values (strings, ints, etc.),map_objectthen hits thenot isinstance(source_obj, dict)check and logs a warning:This happens for every scalar field without an explicit range, producing many spurious warnings during normal transforms.
Root Cause
In
_map_value_by_range(object_transformer.py), whensource_class_slot.rangeisNoneand there are noany_ofenums, the method falls through to the recursivemap_objectcall at line 611. For scalar values,map_objectreceivessource_type=None, which isn't inall_types()orall_enums(), the value isn't a dict, so it logs the warning and returns the value unchanged.The recursion is pointless for scalars when there's no range — there's nothing to map.
Reproducer
Fix
In
_map_value_by_range, whenrangeisNone/"Any"and there are noany_ofenums, return scalar values directly instead of recursing: