Skip to content

Commit

Permalink
Use stdlib toml provider on Python >= 3.11. Switch to tomli otherwise (
Browse files Browse the repository at this point in the history
  • Loading branch information
wimglenn committed Sep 12, 2023
1 parent 8e4bc71 commit 8fb5f70
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 3 deletions.
16 changes: 16 additions & 0 deletions configurator/_toml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import io

try:
import tomllib
except ImportError:
import tomli as tomllib


def load(f, *, parse_float=float):
# wrapper around tomllib.load to be more forgiving of streams opened in text mode
if isinstance(f, io.TextIOWrapper):
return tomllib.load(f.buffer, parse_float=parse_float)
elif isinstance(f, io.StringIO):
return tomllib.loads(f.getvalue(), parse_float=parse_float)
else:
return tomllib.load(f, parse_float=parse_float)
6 changes: 4 additions & 2 deletions configurator/parsers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import defaultdict
from importlib import import_module


class ParseError(Exception):
Expand All @@ -10,9 +11,10 @@ class ParseError(Exception):

class Parsers(defaultdict):

# file extension: module name, method name
supported = {
'json': ('json', 'load'),
'toml': ('toml', 'load'),
'toml': ('configurator._toml', 'load'),
'yml': ('yaml', 'safe_load'),
'yaml': ('yaml', 'safe_load'),
}
Expand All @@ -23,5 +25,5 @@ def __missing__(self, extension):
except KeyError:
raise ParseError('No parser found for {!r}'.format(extension))
else:
module = __import__(module_name)
module = import_module(module_name)
return getattr(module, parser_name)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
python_requires=">=3.6",
extras_require=dict(
yaml=['pyyaml'],
toml=['toml'],
toml=['tomli; python_version < "3.11"'],
test=[
'jinja2',
'mock',
Expand Down
65 changes: 65 additions & 0 deletions tests/test_toml_loading.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import pytest
from testfixtures import compare

from configurator import Config


def test_load_toml_from_path_implicit_parser(tmp_path):
path = tmp_path / 'test.toml'
path.write_bytes(b'k = "v"')
config = Config.from_path(path)
compare(config.k, "v")


def test_load_toml_from_path_explicit_parser(tmp_path):
path = tmp_path / 'test.toml'
path.write_bytes(b'k = "v"')
parser = Config.parsers['toml']
config = Config.from_path(path, parser)
compare(config.k, "v")


def test_load_toml_from_byte_stream_implicit_parser(tmp_path):
path = tmp_path / 'test.toml'
path.write_bytes(b'k = "v"')
with path.open(mode="rb") as stream:
config = Config.from_stream(stream)
compare(config.k, "v")


def test_load_toml_from_byte_stream_explicit_parser(tmp_path):
path = tmp_path / 'test.toml'
path.write_bytes(b'k = "v"')
parser = Config.parsers['toml']
with path.open(mode="rb") as stream:
config = Config.from_stream(stream, parser)
compare(config.k, "v")


def test_load_toml_from_text_stream_implicit_parser(tmp_path):
path = tmp_path / 'test.toml'
path.write_bytes(b'k = "v"')
with path.open(mode="rt") as stream:
config = Config.from_stream(stream)
compare(config.k, "v")


def test_load_toml_from_text_stream_explicit_parser(tmp_path):
path = tmp_path / 'test.toml'
path.write_bytes(b'k = "v"')
parser = Config.parsers['toml']
with path.open(mode="rt") as stream:
config = Config.from_stream(stream, parser)
compare(config.k, "v")


def test_load_toml_from_text():
parser = Config.parsers['toml']
config = Config.from_text('k = "v"', parser)
compare(config.k, "v")


def test_load_toml_from_bytes():
parser = Config.parsers['toml']
config = Config.from_text(b'k = "v"', parser)
compare(config.k, "v")

0 comments on commit 8fb5f70

Please sign in to comment.