Julian / venvs

venvs creates virtualenvs
https://pypi.org/project/venvs/
MIT License
17 stars 12 forks source link

[WIP] Fix [ [ "t", "w", "i", ... in installed.toml #93

Closed altendky closed 4 years ago

altendky commented 4 years ago

See #92

altendky commented 4 years ago

So there's an exemplary fix (in the bad way, not the good way). Basically, seems that toml.dumps() isn't handling the tomlkit.items.String well.

https://github.com/sdispater/tomlkit/blob/8f1baf099f148c3cec1708e4c3691eea2957fc81/tomlkit/items.py#L1202

class String(unicode, Item):

Ok, this time I looked sensibly at toml and I think I found it... and it's not isinstance() since that would work.

https://github.com/uiri/toml/blob/f4f0b84fd84265b296312153628cd9dbd5961664/toml/encoder.py#L134-L145

        self.dump_funcs = {
            str: _dump_str,
            unicode: _dump_str,
            list: self.dump_list,
            bool: lambda v: unicode(v).lower(),
            int: lambda v: v,
            float: _dump_float,
            Decimal: _dump_float,
            datetime.datetime: lambda v: v.isoformat().replace('+00:00', 'Z'),
            datetime.time: _dump_time,
            datetime.date: lambda v: v.isoformat()
        }

https://github.com/uiri/toml/blob/f4f0b84fd84265b296312153628cd9dbd5961664/toml/encoder.py#L176-L178

        dump_fn = self.dump_funcs.get(type(v))
        if dump_fn is None and hasattr(v, '__iter__'):
            dump_fn = self.dump_funcs[list]

So it's checking for str by way of the dict lookup rather than issubclass() or isinstance() being involved then noting that it is in fact iterable and using the list dumper.

So the question is, where do we want to solve this? Depending on response to uiri/toml#273, maybe I'll PR. But maybe we want to keep controlled elsewhere for some reason.

altendky commented 4 years ago

It looks like a customized encoder should be easy too. Something like at least.

class TomlEncoderForTomlkitTypes(TomlEncoder):
    def __init__(self, _dict=dict, preserve=False):
        super(TomlEncoderForTomlkitTypes, self).__init__(*args, **kwargs)
        self.dump_funcs[tomlkit.items.String] = self.dump_funcs[str]

dumped = toml.dumps(d, encoder=TomlEncoderForTomlkitTypes())
Julian commented 4 years ago

To be honest, given that the installed.toml code has to be rewritten anyways to use _config.Config, and that this use case really doesn't need TOML (it's not for humans, it's just a cache) my plan was to replace things with JSON (basically we need to write out a lockfile equivalent of a _config.Config, and then just simply check against it when converging).