libucl icon indicating copy to clipboard operation
libucl copied to clipboard

Example does not work as described.

Open jmgurney opened this issue 5 years ago • 8 comments

So, I was looking at the example in the README.md of the project. I noticed that the first example didn't end up w/ an object named section, despite later in it saying that it should be. I decided to import this into libucl, and export the json, and see how it'd work out, but I got a bigger surprise, the array didn't work like the example implied it should.

This is under python's ucl library, so this COULD be a python library issue. This is using libucl 0.8.1.

$python
Python 3.7.5 (default, Oct 18 2019, 23:59:39) 
[Clang 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ucl
>>> examp = '''param = value;
... section {
...     param = value;
...     param1 = value1;
...     flag = true;
...     number = 10k;
...     time = 0.2s;
...     string = "something";
...     subsection {
...         host = {
...             host = "hostname";
...             port = 900;
...         }
...         host = {
...             host = "hostname";
...             port = 901;
...         }
...     }
... }'''
>>> u = ucl.load(examp)
>>> print(repr(u))
{'param': 'value', 'section': {'param': 'value', 'param1': 'value1', 'flag': True, 'number': 10000, 'time': '0.2s', 'string': 'something', 'subsection': {'host': {'host': 'hostname', 'port': 900}}}}
>>> import json
>>> print(repr(json.dumps(u)))
'{"param": "value", "section": {"param": "value", "param1": "value1", "flag": true, "number": 10000, "time": "0.2s", "string": "something", "subsection": {"host": {"host": "hostname", "port": 900}}}}'
>>> ^D
$echo '{"param": "value", "section": {"param": "value", "param1": "value1", "flag": true, "number": 10000, "time": "0.2s", "string": "something", "subsection": {"host": {"host": "hostname", "port": 900}}}}' | python -m json.tool
{
    "param": "value",
    "section": {
        "param": "value",
        "param1": "value1",
        "flag": true,
        "number": 10000,
        "time": "0.2s",
        "string": "something",
        "subsection": {
            "host": {
                "host": "hostname",
                "port": 900
            }
        }
    }
}

I expected that the JSON output would match the example in JSON, but there are a number of differences, that being the section is missing in the JSON example, and the list in host in the subsection object, did not get listed as a host.

There is also the fact that number, time and string keys are missing from the section, but that is likely a simple issue w/ the examples not being updated.

jmgurney avatar Sep 10 '20 00:09 jmgurney

if I'm given guidance on what the examples should look like, I'm more than willing to submit an update.

jmgurney avatar Sep 10 '20 00:09 jmgurney

That works fine with Lua.

local u = require "ucl"
local p = u.parser()
p:parse_file('tt.ucl')
print(u.to_json(p:get_object()))

gives:

{
    "section": {
        "number": 10000,
        "subsection": {
            "host": [
                {
                    "host": "hostname",
                    "port": 900
                },
                {
                    "host": "hostname",
                    "port": 901
                }
            ]
        },
        "flag": true,
        "param1": "value1",
        "time": 0.200000,
        "string": "something",
        "param": "value"
    },
    "param": "value"
}

Unfortunately, I don't know the details about how Python part works as it has been contributed by another person.

vstakhov avatar Sep 14 '20 19:09 vstakhov

I'll take a look at the python. But will you be updating the JSON in the example to match the above? I only even tried this because of the mismatch.

jmgurney avatar Sep 14 '20 21:09 jmgurney

Ok, looks like lua is treating objects as arrays in special, undocumented cases (at least I couldn't find anything about checking obj->next in libucl/doc): https://github.com/vstakhov/libucl/blob/master/lua/lua_ucl.c#L156

Which is why it works, and it doesn't work on the Python code: https://github.com/vstakhov/libucl/blob/master/python/src/uclmodule.c#L46

jmgurney avatar Sep 14 '20 22:09 jmgurney

Yes, multi-value keys were the biggest design mistake in UCL, I agree :(

vstakhov avatar Sep 14 '20 22:09 vstakhov

why not simply change libucl to return the object as an array when that happens? at least it'd give expected results in that consumers should be treating them as arrays instead of objects.

It'd also catch cases where consumers weren't expecting an object become array, and also handle the POLA case where the consumer wasn't handling it (e.g. this python library), and the other objects just disappear, or ignored causing the end user no idea WHY their configuration isn't working the way they expected it to.

jmgurney avatar Sep 14 '20 22:09 jmgurney

why not simply change libucl to return the object as an array when that happens?

libucl has a parser flag to do that: UCL_PARSER_NO_IMPLICIT_ARRAYS

vstakhov avatar Sep 14 '20 22:09 vstakhov

Ok, adding the flag fixes UCL_PARSER_NO_IMPLICIT_ARRAYS the python test case. I'll submit a PR for Python module including a test for this case.

jmgurney avatar Sep 14 '20 22:09 jmgurney