2

I'm migrating my project configurations into a separate config file so that different parts of my project can access them independently. I've been using *.toml files for this lately and I quite like them.

In this project, for the first time, I have some constants that are complex numbers, or even arrays of complex numbers. I just discovered that *.toml doesn't support complex values. Nothing turns up on google or stackoverflow when I search for "toml complex numbers," so I seem to be the first person to encounter this problem.

How does anyone keep a human-readable config file with complex numbers in it? I can certainly create 2 values, one for the real part and one for the imaginary part, but I wouldn't consider that "human readable" for my purposes. I am not married to the *.toml format and am willing to switch to another config file format that supports this.

Below is a MWE of what I'm trying to do:

>>> import toml

>>> pretend_file = 'my_real_number = 3'
>>> data = toml.loads(pretend_file)
>>> print(data)
{'my_real_number': 3}

>>> new_pretend_file = 'my_complex_number = 3 + 3j'
>>> data = toml.loads(new_pretend_file)
raise TomlDecodeError(str(err), original, pos)
toml.decoder.TomlDecodeError: invalid literal for int() with base 0: '3 + 3j' (line 1 column 1 char 0)

Edit: Based on a suggestion by Brian, I suppose one could use a string. Would it be poor form to use ast.literal_eval? For example:

>>> import toml
>>> from ast import literal_eval
>>> pretend_file = "my_complex_array = '[2+2j, 3+3j]'"
>>> data = toml.loads(pretend_file)
>>> np.array(literal_eval(data['my_complex_array']), dtype=complex)
array([2.+2.j, 3.+3.j])
Drphoton
  • 164
  • 9

1 Answers1

1

A few options come to mind, in addition to storing the real and imaginary parts separately as you mention.

1. Use a two-element array

data = toml.loads("x = [3, 4]")
print(data)                 # {'x': [3, 4]}
print(complex(*data["x"]))  # 3+4j

This also generalizes well for arrays of complex numbers:

data = toml.loads("x = [[1,2], [3,4]]")
print(data)                              # {'x': [[1, 2], [3, 4]]}
print([complex(*x) for x in data["x"]])  # [(1+2j), (3+4j)]

2. Use an inline table

data = toml.loads("x = {r = 3, i = 4}")
print(data)                                     # {'x': {'r': 3, 'i': 4}}
print(complex(data["x"]["r"], data["x"]["i"]))  # (3+4j)

This approach also generalizes to arrays of complex numbers:

data = toml.loads("x = [{r = 1, i = 2}, {r = 3, i = 4}]")
print(data)                                          # {'x': [{'r': 1, 'i': 2},{'r': 3, 'i': 4}]}
print([complex(x["r"], x["i"]) for x in data["x"]])  # [(1+2j),(3+4j)]

3. Use a string

data = toml.loads('x = "3+4j"')
print(data)                # {'x': '3+4j'}
print(complex(data["x"]))  # (3+4j)
Brian61354270
  • 8,690
  • 4
  • 21
  • 43
  • Not a bad suggestion but I’m not thrilled with it. I don’t need to use toml files if there’s a better alternative available. – Drphoton Jun 25 '22 at 16:51