9.1. TOML

9.1.1. SetUp

>>> import tomllib

9.1.2. From String

>>> toml_str = """
... python-version = "3.11.3"
... python-implementation = "CPython"
... """
>>>
>>> data = tomllib.loads(toml_str)
>>> data
{'python-version': '3.11.3', 'python-implementation': 'CPython'}

9.1.3. From File

>>> with open('pyproject.toml', 'rb') as f:  
...     data = tomllib.load(f)

9.1.4. Conversion Table

TOML

Python

table

dict

string

str

integer

int

float

float (configurable with parse_float)

boolean

bool

offset date-time

datetime.datetime (tzinfo attribute set to an instance of datetime.timezone)

local date-time

datetime.datetime (tzinfo attribute set to None)

local date

datetime.date

local time

datetime.time

array

list

9.1.5. Example

[project]
name = "myproject"
version = "1.0.0"
requires-python = ">=3.11"
authors = [{name = "Mark Watney", email = "mwatney@nasa.gov"}]
readme = "README.md"
license = {file = "LICENSE"}
keywords = ["ares", "mars", "nasa", "human-spaceflight"]
dependencies = [
    "django == 4.2.*",
    "django-ninja == 0.19.*"]

9.1.6. Assignments

Code 9.7. Solution
"""
* Assignment: TOML Load Version
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 min

English:
    1. Read configuration from `FILE`
    2. Define `result: dict` with version read from config
    3. Use `tomllib.load()`
    4. Run doctests - all must succeed

Polish:
    1. Wczytaj konfigurację z `FILE`
    2. Zdefiniuj `result: dict` z werją wczytaną z konfiguracji
    3. Użyj `tomllib.load()`
    4. Uruchom doctesty - wszystkie muszą się powieść

Hint:
    * open(filename, mode='rb')
    * import tomllib
    * tomllib.load()

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from pprint import pprint
    >>> from os import remove
    >>> remove(FILE)

    >>> assert result is not Ellipsis, \
    'Assign result to variable: `result`'
    >>> assert type(result) is str, \
    'Variable `result` has invalid type, should be str'

    >>> pprint(result)
    '1.0.0'
"""
import tomllib


FILE = '_temporary.toml'

DATA = b"""
project = 'My App'
version = '1.0.0'
"""

with open(FILE, mode='wb') as file:
    file.write(DATA)


# Read configuration from `FILE`
# Define `result: dict` with version read from config
# type: dict[str, str|int]
result = ...

Code 9.8. Solution
"""
* Assignment: TOML Load Database
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min

English:
    1. Read configuration from `FILE`
    2. Define `result: dict` with database config
    3. Use `tomllib.load()`
    4. Run doctests - all must succeed

Polish:
    1. Wczytaj konfigurację z `FILE`
    2. Zdefiniuj `result: dict` z konfiguracją bazy danych
    3. Użyj `tomllib.load()`
    4. Uruchom doctesty - wszystkie muszą się powieść

Hint:
    * open(filename, mode='rb')
    * import tomllib
    * tomllib.load()

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from os import remove

    >>> assert result is not Ellipsis, \
    'Assign result to variable: `result`'
    >>> assert type(result) is dict, \
    'Variable `result` has invalid type, should be dict'

    >>> assert result['hostname'] == '127.0.0.1'
    >>> assert result['port'] == 5432
    >>> assert result['username'] == 'mwatney'
    >>> assert result['password'] == 'Ares3'
    >>> assert result['database'] == 'nasa'

    >>> remove(FILE)
"""
import tomllib


FILE = '_temporary.toml'

DATA = b"""
project = 'My App'
version = '1.0.0'

[database]
hostname = '127.0.0.1'
port = 5432
username = 'mwatney'
password = 'Ares3'
database = 'nasa'
"""

with open(FILE, mode='wb') as file:
    file.write(DATA)


# Read configuration from `FILE`
# Define `result: dict` with database config
# type: dict[str, str|int]
result = ...


Code 9.9. Solution
"""
* Assignment: TOML Load Authors
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min

English:
    1. Read configuration from `FILE`
    2. Define `result: datetime` with release date
    3. Use `tomllib.load()`
    4. Run doctests - all must succeed

Polish:
    1. Wczytaj konfigurację z `FILE`
    2. Zdefiniuj `result: datetime` z datą wdrożenia
    3. Użyj `tomllib.load()`
    4. Uruchom doctesty - wszystkie muszą się powieść

Hint:
    * open(filename, mode='rb')
    * import tomllib
    * tomllib.load()

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from pprint import pprint
    >>> from datetime import datetime
    >>> from os import remove
    >>> remove(FILE)

    >>> assert result is not Ellipsis, \
    'Assign result to variable: `result`'
    >>> assert type(result) is datetime, \
    'Variable `result` has invalid type, should be datetime'

    >>> pprint(result)
    datetime.datetime(2020, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
"""
import tomllib


FILE = '_temporary.toml'

DATA = b"""
project = 'My App'
version = '1.0.0'

[database]
hostname = '127.0.0.1'
port = 5432
username = 'mwatney'
password = 'Ares3'
database = 'nasa'

[metadata]
release_date = 2020-01-01T00:00:00Z
"""

with open(FILE, mode='wb') as file:
    file.write(DATA)


# Read configuration from `FILE`
# Define `result: datetime` with release date
# type: dict[str, str|int]
result = ...


Code 9.10. Solution
"""
* Assignment: TOML Load Authors
* Complexity: easy
* Lines of code: 4 lines
* Time: 5 min

English:
    1. Read configuration from `FILE`
    2. Define `result: list[str]` with author emails
    3. Use `tomllib.load()`
    4. Run doctests - all must succeed

Polish:
    1. Wczytaj konfigurację z `FILE`
    2. Zdefiniuj `result: list[str]` z adresami email autorów
    3. Użyj `tomllib.load()`
    4. Uruchom doctesty - wszystkie muszą się powieść

Hint:
    * open(filename, mode='rb')
    * import tomllib
    * tomllib.load()

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from pprint import pprint
    >>> from os import remove
    >>> remove(FILE)

    >>> assert result is not Ellipsis, \
    'Assign result to variable: `result`'
    >>> assert type(result) is list, \
    'Variable `result` has invalid type, should be list'

    >>> result = sorted(result)
    >>> pprint(result)
    ['avogel@nasa.gov',
     'bjohanssen@nasa.gov',
     'cbeck@nasa.gov',
     'mlewis@nasa.gov',
     'mwatney@nasa.gov',
     'rmartinez@nasa.gov']
"""
import tomllib


FILE = '_temporary.toml'

DATA = b"""
project = 'My App'
version = '1.0.0'

[database]
hostname = '127.0.0.1'
port = 5432
username = 'mwatney'
password = 'Ares3'
database = 'nasa'

[metadata]
release_date = 2020-01-01T00:00:00Z
authors = [
    { name = 'Mark Watney', email = 'mwatney@nasa.gov' },
    { name = 'Melisa Lewis', email = 'mlewis@nasa.gov' },
    { name = 'Rick Martinez', email = 'rmartinez@nasa.gov' },
    { name = 'Alex Vogel', email = 'avogel@nasa.gov' },
    { name = 'Beth Johanssen', email = 'bjohanssen@nasa.gov' },
    { name = 'Chris Beck', email = 'cbeck@nasa.gov' },
]
"""

with open(FILE, mode='wb') as file:
    file.write(DATA)


# Read configuration from `FILE`
# Define `result: list[str]` with author emails
# type: dict[str, str|int]
result = ...


Code 9.11. Solution
"""
* Assignment: TOML Load Stats
* Complexity: easy
* Lines of code: 3 lines
* Time: 5 min

English:
    1. Game characters stats are written to `FILE`
    2. Define function `get_stats(name: str) -> dict`
        a. Parameter `name: str`, example: 'Sarevok'
        b. Returns `dict` with character named `name` stats
    3. Use `tomllib.load()`
    4. Run doctests - all must succeed

Polish:
    1. Statystyki postaci z gry zapisano do `FILE`
    2. Zdefiniuj funkcję `get_stats(name: str) -> dict`
        a. Parametr `name: str`, przykład: 'Sarevok'
        b. Zwraca `dict` ze statystykami postaci o imieniu `name`
    3. Użyj `tomllib.load()`
    4. Uruchom doctesty - wszystkie muszą się powieść

Hint:
    * open(filename, mode='rb')
    * import tomllib
    * tomllib.load()

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from os import remove

    >>> imoen = get_stats('Imoen')
    >>> assert imoen['character_class'] == 'Thief'
    >>> assert imoen['race'] == 'Human'
    >>> assert imoen['alignment'] == 'Neutral Good'
    >>> assert imoen['strength'] == 9
    >>> assert imoen['dexterity'] == 18
    >>> assert imoen['constitution'] == 16
    >>> assert imoen['intelligence'] == 17
    >>> assert imoen['wisdom'] == 11
    >>> assert imoen['charisma'] == 16

    >>> minsc = get_stats('Minsc')
    >>> assert minsc['character_class'] == 'Ranger'
    >>> assert minsc['race'] == 'Human'
    >>> assert minsc['alignment'] == 'Neutral Good'
    >>> assert minsc['strength'] == 18
    >>> assert minsc['dexterity'] == 15
    >>> assert minsc['constitution'] == 15
    >>> assert minsc['intelligence'] == 8
    >>> assert minsc['wisdom'] == 6
    >>> assert minsc['charisma'] == 9

    >>> neera = get_stats('Neera')
    >>> assert neera['character_class'] == 'Wild Mage'
    >>> assert neera['race'] == 'Half-elf'
    >>> assert neera['alignment'] == 'Chaotic Neutral'
    >>> assert neera['strength'] == 11
    >>> assert neera['dexterity'] == 17
    >>> assert neera['constitution'] == 14
    >>> assert neera['intelligence'] == 17
    >>> assert neera['wisdom'] == 10
    >>> assert neera['charisma'] == 11

    >>> sarevok = get_stats('Sarevok')
    >>> assert sarevok['character_class'] == 'Fighter'
    >>> assert sarevok['race'] == 'Human'
    >>> assert sarevok['alignment'] == 'Chaotic Evil'
    >>> assert sarevok['strength'] == 18
    >>> assert sarevok['dexterity'] == 17
    >>> assert sarevok['constitution'] == 18
    >>> assert sarevok['intelligence'] == 17
    >>> assert sarevok['wisdom'] == 10
    >>> assert sarevok['charisma'] == 15

    >>> remove(FILE)
"""
import tomllib


FILE = '_temporary.toml'

DATA = b"""
[Imoen]
character_class = 'Thief'
race = 'Human'
alignment = 'Neutral Good'
strength = 9
dexterity = 18
constitution = 16
intelligence = 17
wisdom = 11
charisma = 16

[Minsc]
character_class = 'Ranger'
race = 'Human'
alignment = 'Neutral Good'
strength = 18
dexterity = 15
constitution = 15
intelligence = 8
wisdom = 6
charisma = 9

[Neera]
character_class = 'Wild Mage'
race = 'Half-elf'
alignment = 'Chaotic Neutral'
strength = 11
dexterity = 17
constitution = 14
intelligence = 17
wisdom = 10
charisma = 11

[Sarevok]
character_class = 'Fighter'
race = 'Human'
alignment = 'Chaotic Evil'
strength = 18
dexterity = 17
constitution = 18
intelligence = 17
wisdom = 10
charisma = 15
"""

with open(FILE, mode='wb') as file:
    file.write(DATA)


# Game characters stats are written to `FILE`
# Define function `get_stats(name: str) -> dict`
#  a. Parameter `name: str`, example: 'Sarevok'
#  b. Returns `dict` with character named `name` stats
# Use `tomllib.load()`
# type: Callable[[str], dict]
def get_stats(name: str) -> dict:
    ...