Skip to content
44 changes: 38 additions & 6 deletions lkml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def parse_args(args: Sequence) -> argparse.Namespace:
)
)
parser.add_argument(
"file", type=argparse.FileType("r"), help="path to the LookML file to parse"
"file", type=argparse.FileType("r+"), help="path to the LookML file to parse"
)
parser.add_argument(
"-v",
Expand All @@ -96,6 +96,27 @@ def parse_args(args: Sequence) -> argparse.Namespace:
help="increase logging verbosity to debug",
)

group = parser.add_mutually_exclusive_group()
group.add_argument(
"--json",
action="store_true",
default=True,
help="return a JSON string (default)",
)
group.add_argument(
"--lookml",
action="store_true",
default=False,
help="return a LookML string",
)
group.add_argument(
"-w",
"--write",
action="store_true",
default=False,
help="parse and write back to file",
)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use case for parsing from a file and writing back to the same file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lkml parser/dumper does a great job at cleaning up lkml files (separating measures from dimensions, correcting the indentation, etc.), the option to write it back to file would allow to use lkml as a auto-formatter in text editors, pre-commits, CI checks, etc. (like running black on .py files).


return parser.parse_args(args)


Expand All @@ -116,8 +137,19 @@ def cli():

logging.getLogger().setLevel(args.log_level)

result: dict = load(args.file)
args.file.close()

json_string = json.dumps(result, indent=2)
print(json_string)
try:
result: dict = load(args.file)

if args.write:
args.file.seek(0)
dump(result, args.file)
args.file.truncate()
elif args.lookml:
lookml_string = dump(result)
print(lookml_string)
elif args.json:
json_string = json.dumps(result, indent=2)
print(json_string)

finally:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileType objects dont work with context managers, this makes sure the file is closed even if they cannot be parsed.

args.file.close()
19 changes: 19 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ def test_absence_of_debug_flag_is_parsed_to_log_level_warn(lookml_path):
assert args.log_level == logging.WARN


def test_default_option(lookml_path):
args = lkml.parse_args([lookml_path])
assert args.json is True
assert args.lookml is args.write is False


def test_options(lookml_path):
args = lkml.parse_args([lookml_path, "--json"])
assert args.json is True
args = lkml.parse_args([lookml_path, "--lookml"])
assert args.lookml is True
args = lkml.parse_args([lookml_path, "--write"])
assert args.write is True
args = lkml.parse_args([lookml_path, "-w"])
assert args.write is True
with pytest.raises(SystemExit):
args = lkml.parse_args([lookml_path, "--json", "--lookml"])


@patch("lkml.load")
@patch("lkml.parse_args")
def test_run_cli(mock_parse_args, mock_load, lookml_path):
Expand Down