python-poetry / tomlkit

Style-preserving TOML library for Python
MIT License
699 stars 100 forks source link

Sign change when doing math gives invalid number #341

Closed michi12321 closed 6 months ago

michi12321 commented 7 months ago

Bug:

>>> d = tomlkit.parse('x=-3.1415')
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))

returns:

a=+3.1415

>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))

returns:

a=--3.1415

Subsequent parsing raises tomlkit.exceptions.InvalidNumberError.

Of course there is an easy workaround using type conversion: d['x'] = float(d['x'])*-1.

JamesParrott commented 6 months ago

I'mm not sure where the "a" is coming from in your example when everything is done on the "x" key. Nor how it is possible to get Python to print a float as "--3.1415" at all.

Suffice to say I could not reproduce the output posted (on Windows 11, Python 3.11, Tomlkit 0.11.8):

>>> d=tomlkit.parse('x=-3.1415')
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))
x=3.1415
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))
x=-3.1415

Please provide a minimal reproducible example and details of the environment. Until then I suggest this issue be closed.

michi12321 commented 6 months ago

Hi James, thanks for your time! The 'a' is of course supposed to be a 'x'... I can confirm that this issue doesn't appear in tomlkit 0.11.8 . I was using tomlkit 0.12 on different versions of python (3.11+3.12) and different OS (Win10, Linux) Minimal reproducible example below:

>>> import tomlkit
>>> d = tomlkit.parse('x=-3.14')
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))
x=+3.14
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))
x=--3.14
>>> tomlkit.parse(tomlkit.dumps(d))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/michi/.virtualenvs/tk/lib/python3.11/site-packages/tomlkit/api.py", line 86, in parse
    return Parser(string).parse()
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/michi/.virtualenvs/tk/lib/python3.11/site-packages/tomlkit/parser.py", line 139, in parse
    item = self._parse_item()
           ^^^^^^^^^^^^^^^^^^
  File "/home/michi/.virtualenvs/tk/lib/python3.11/site-packages/tomlkit/parser.py", line 238, in _parse_item
    return self._parse_key_value(True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/michi/.virtualenvs/tk/lib/python3.11/site-packages/tomlkit/parser.py", line 331, in _parse_key_value
    val = self._parse_value()
          ^^^^^^^^^^^^^^^^^^^
  File "/home/michi/.virtualenvs/tk/lib/python3.11/site-packages/tomlkit/parser.py", line 456, in _parse_value
    raise self.parse_error(InvalidNumberError)
tomlkit.exceptions.InvalidNumberError: Invalid number at line 1 col 8
JamesParrott commented 6 months ago

You're welcome. Sorry I thought it was Python producing the --, whereas it's in the string from tomlkit.dumps. I can reproduce it now:

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import tomlkit
>>> d = tomlkit.parse('x=-3.14')
>>> d
{'x': -3.14}
>>> print(tomlkit.dumps(d))
x=-3.14
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))
x=+3.14
>>> d['x'] *= -1
>>> print(tomlkit.dumps(d))
x=--3.14
>>> tomlkit.__version__
'0.12.0'

Anyway, note that tomlkit.loads returns a tomlkit.toml_document.TOMLDocument, which has the same __repr__ as a dict but is at best, a subclass. A normal Python dict can be formed from its .items(). But tomlkit will still remember its starting state and render it as --1.

But you're quite right. Integer values in tables seem to cycle through +, +, +, -, ... when multiplied by -1 (i.e. not just +,-,+,-,...):

python -ic "import tomlkit as tk"
>>> d =  tk.parse('x=-3')
>>> for __ in range(12):
...   d['x'] *= -1; print(tk.dumps(d))
...
x=+3
x=--3
x=3
x=-3
x=+3
x=--3
x=3
x=-3
x=+3
x=--3
x=3
x=-3

And Float values can never be negative at all:

>>> d =  tk.parse('x=-3.14')
>>> for __ in range(6):
...   d['x'] *= -1; print(tk.dumps(d))
...
x=+3.14
x=--3.14
x=+3.14
x=--3.14
x=+3.14
x=--3.14