lkml
lkml copied to clipboard
Fix boolean value parsing to return Python booleans
Summary
This PR fixes #15 by implementing proper boolean parsing in the LKML parser. Boolean values like yes, no, true, and false are now correctly converted to Python bool objects instead of remaining as strings.
Changes
Core Implementation
-
Modified
DictVisitor.visit_token()inlkml/simple.pyto:- Check if token is quoted (using
QuotedSyntaxToken) - if so, preserve as string - Convert unquoted boolean strings (
yes/no/true/false) to Pythonboolobjects - Handle case-insensitive matching for boolean values
- Check if token is quoted (using
-
Updated
DictParser.parse_any()to handle boolean type during serialization:- Added
boolto accepted types - Convert Python booleans back to
yes/nofor LKML output
- Added
Test Coverage
Added comprehensive tests in tests/test_simple.py:
test_boolean_parsing_yes_no- Basic yes/no conversiontest_boolean_parsing_true_false- Basic true/false conversiontest_boolean_parsing_case_insensitive- Case insensitive handlingtest_boolean_parsing_non_boolean_strings- Non-boolean strings remain unchangedtest_boolean_round_trip- Round-trip serialization works correctlytest_quoted_boolean_strings_remain_strings- Quoted values remain as stringstest_mixed_quoted_unquoted_booleans- Mixed quoted/unquoted in same structuretest_filter_with_quoted_boolean_values- Filter blocks with quoted booleanstest_case_sensitivity_with_quoted_values- Case preservation for quoted valuestest_edge_cases_quoted_vs_unquoted- Edge cases and empty strings
Examples
Before (incorrect):
>>> import lkml
>>> parsed = lkml.load('view: test { dimension: field { hidden: yes } }')
>>> parsed['views'][0]['dimensions'][0]['hidden']
'yes' # String, not boolean\!
After (correct):
>>> import lkml
>>> parsed = lkml.load('view: test { dimension: field { hidden: yes } }')
>>> parsed['views'][0]['dimensions'][0]['hidden']
True # Proper Python boolean
>>> # Quoted values remain as strings
>>> parsed = lkml.load('view: test { dimension: field { label: "yes" } }')
>>> parsed['views'][0]['dimensions'][0]['label']
'yes' # String, as expected
Behavior Summary
- ✅
hidden: yes→True(bool) - ✅
primary_key: no→False(bool) - ✅
suggestions: true→True(bool) - ✅
can_filter: false→False(bool) - ✅
label: "yes"→"yes"(str) - ✅
value: "true"→"true"(str) - ✅ Case insensitive for unquoted values
- ✅ Case preserved for quoted values
- ✅ Round-trip serialization works correctly
Fixes #15