From 748cde83aefe91380d8133a6e44905d373f8725f Mon Sep 17 00:00:00 2001 From: Kent Pitman Date: Wed, 25 Oct 2023 15:37:46 -0400 Subject: [PATCH] Refactor to make an extra entry point for type hinting. --- dcicutils/bundle_utils.py | 47 ++++++++++++++++++++++----------------- test/test_bundle_utils.py | 18 +++++++-------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/dcicutils/bundle_utils.py b/dcicutils/bundle_utils.py index 2914e157d..2c6304e8b 100644 --- a/dcicutils/bundle_utils.py +++ b/dcicutils/bundle_utils.py @@ -316,9 +316,25 @@ def set_path_value(cls, datum: Union[List, Dict], path: ParsedHeader, value: Any cls.set_path_value(datum[key], more_path, value) @classmethod - def find_type_hint(cls, parsed_header: Optional[ParsedHeader], schema: Any, - context: Optional[TypeHintContext] = None): + def find_type_hint_for_subschema(cls, subschema: Any, context: Optional[TypeHintContext] = None): + if subschema is not None: + t = subschema.get('type') + if t == 'string': + enum = subschema.get('enum') + if enum: + mapping = {e.lower(): e for e in enum} + return EnumHint(mapping) + link_to = subschema.get('linkTo') + if link_to and context.schema_exists(link_to): + return RefHint(schema_name=link_to, context=context) + elif t in ('integer', 'float', 'number'): + return NumHint(declared_type=t) + elif t == 'boolean': + return BoolHint() + @classmethod + def find_type_hint_for_parsed_header(cls, parsed_header: Optional[ParsedHeader], schema: Any, + context: Optional[TypeHintContext] = None): def finder(subheader, subschema): if not parsed_header: return None @@ -326,28 +342,15 @@ def finder(subheader, subschema): [key1, *other_headers] = subheader if isinstance(key1, str) and isinstance(subschema, dict): if subschema.get('type') == 'object': - def1 = subschema.get('properties', {}).get(key1) + subsubschema = subschema.get('properties', {}).get(key1) if not other_headers: - if def1 is not None: - t = def1.get('type') - if t == 'string': - enum = def1.get('enum') - if enum: - mapping = {e.lower(): e for e in enum} - return EnumHint(mapping) - link_to = def1.get('linkTo') - if link_to and context.schema_exists(link_to): - return RefHint(schema_name=link_to, context=context) - elif t in ('integer', 'float', 'number'): - return NumHint(declared_type=t) - elif t == 'boolean': - return BoolHint() - else: - pass # fall through to asking super() + hint = cls.find_type_hint_for_subschema(subsubschema, context=context) + if hint: + return hint else: pass # fall through to asking super() else: - return finder(subheader=other_headers, subschema=def1) + return finder(subheader=other_headers, subschema=subsubschema) return finder(subheader=parsed_header, subschema=schema) @@ -609,7 +612,9 @@ def compile_type_hints(self, tab_name: str) -> OptionalTypeHints: for required_header in self._schema_required_headers(schema): if required_header not in parsed_headers: self.note_problem("Missing required header") - positional_type_hints = [ItemTools.find_type_hint(parsed_header, schema, context=self) if schema else None + positional_type_hints = [(ItemTools.find_type_hint_for_parsed_header(parsed_header, schema, context=self) + if schema + else None) for parsed_header in parsed_headers] type_hints = OptionalTypeHints(positional_type_hints, positional_breadcrumbs=parsed_headers) return type_hints diff --git a/test/test_bundle_utils.py b/test/test_bundle_utils.py index a95aee1ef..b5d837339 100644 --- a/test/test_bundle_utils.py +++ b/test/test_bundle_utils.py @@ -219,13 +219,13 @@ def test_item_tools_set_path_value(): def test_item_tools_find_type_hint(): - assert ItemTools.find_type_hint(None, 'anything') is None + assert ItemTools.find_type_hint_for_parsed_header(None, 'anything') is None - assert ItemTools.find_type_hint(['foo', 'bar'], None) is None - assert ItemTools.find_type_hint(['foo', 'bar'], "something") is None - assert ItemTools.find_type_hint(['foo', 'bar'], {}) is None + assert ItemTools.find_type_hint_for_parsed_header(['foo', 'bar'], None) is None + assert ItemTools.find_type_hint_for_parsed_header(['foo', 'bar'], "something") is None + assert ItemTools.find_type_hint_for_parsed_header(['foo', 'bar'], {}) is None - actual = ItemTools.find_type_hint(['foo', 'bar'], {"type": "object"}) + actual = ItemTools.find_type_hint_for_parsed_header(['foo', 'bar'], {"type": "object"}) assert actual is None schema = { @@ -236,10 +236,10 @@ def test_item_tools_find_type_hint(): } } } - actual = ItemTools.find_type_hint(['foo', 'bar'], schema) + actual = ItemTools.find_type_hint_for_parsed_header(['foo', 'bar'], schema) assert actual is None - actual = ItemTools.find_type_hint(['foo'], schema) + actual = ItemTools.find_type_hint_for_parsed_header(['foo'], schema) assert isinstance(actual, BoolHint) schema = { @@ -255,10 +255,10 @@ def test_item_tools_find_type_hint(): } } } - actual = ItemTools.find_type_hint(['foo', 'bar'], schema) + actual = ItemTools.find_type_hint_for_parsed_header(['foo', 'bar'], schema) assert isinstance(actual, BoolHint) - actual = ItemTools.find_type_hint(['foo'], schema) + actual = ItemTools.find_type_hint_for_parsed_header(['foo'], schema) assert actual is None