configaroo 0.4.2__tar.gz → 0.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {configaroo-0.4.2/src/configaroo.egg-info → configaroo-0.5.1}/PKG-INFO +3 -3
  2. {configaroo-0.4.2 → configaroo-0.5.1}/README.md +2 -2
  3. {configaroo-0.4.2 → configaroo-0.5.1}/pyproject.toml +12 -5
  4. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/__init__.py +1 -1
  5. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/configuration.py +34 -11
  6. {configaroo-0.4.2 → configaroo-0.5.1/src/configaroo.egg-info}/PKG-INFO +3 -3
  7. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_configuration.py +2 -2
  8. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_print.py +46 -0
  9. {configaroo-0.4.2 → configaroo-0.5.1}/LICENSE +0 -0
  10. {configaroo-0.4.2 → configaroo-0.5.1}/setup.cfg +0 -0
  11. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/exceptions.py +0 -0
  12. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/loaders/__init__.py +0 -0
  13. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/loaders/json.py +0 -0
  14. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/loaders/toml.py +0 -0
  15. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo/py.typed +0 -0
  16. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo.egg-info/SOURCES.txt +0 -0
  17. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo.egg-info/dependency_links.txt +0 -0
  18. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo.egg-info/requires.txt +0 -0
  19. {configaroo-0.4.2 → configaroo-0.5.1}/src/configaroo.egg-info/top_level.txt +0 -0
  20. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_dynamic.py +0 -0
  21. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_environment.py +0 -0
  22. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_json.py +0 -0
  23. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_loaders.py +0 -0
  24. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_toml.py +0 -0
  25. {configaroo-0.4.2 → configaroo-0.5.1}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.4.2
3
+ Version: 0.5.1
4
4
  Summary: Bouncy handling of configuration files
5
5
  Author-email: Geir Arne Hjelle <geirarne@gmail.com>
6
6
  Maintainer-email: Geir Arne Hjelle <geirarne@gmail.com>
@@ -33,9 +33,9 @@ Dynamic: license-file
33
33
  [![Python versions](https://img.shields.io/pypi/pyversions/configaroo.svg)](https://pypi.org/project/configaroo/)
34
34
  [![License](https://img.shields.io/pypi/l/configaroo.svg)](https://github.com/gahjelle/configaroo/blob/main/LICENSE)
35
35
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
36
- [![Linted](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml)
36
+ [![Linted with Ruff](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml)
37
37
  [![Tested with Pytest](https://github.com/gahjelle/configaroo/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/test.yml)
38
- [![Type checked with mypy](https://img.shields.io/badge/type%20checked-mypy-green)](http://mypy-lang.org/)
38
+ [![Type checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
39
39
 
40
40
  Configaroo is a light configuration package for Python that offers the following features:
41
41
 
@@ -4,9 +4,9 @@
4
4
  [![Python versions](https://img.shields.io/pypi/pyversions/configaroo.svg)](https://pypi.org/project/configaroo/)
5
5
  [![License](https://img.shields.io/pypi/l/configaroo.svg)](https://github.com/gahjelle/configaroo/blob/main/LICENSE)
6
6
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
7
- [![Linted](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml)
7
+ [![Linted with Ruff](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml)
8
8
  [![Tested with Pytest](https://github.com/gahjelle/configaroo/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/test.yml)
9
- [![Type checked with mypy](https://img.shields.io/badge/type%20checked-mypy-green)](http://mypy-lang.org/)
9
+ [![Type checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
10
10
 
11
11
  Configaroo is a light configuration package for Python that offers the following features:
12
12
 
@@ -36,13 +36,14 @@ changelog = "https://github.com/gahjelle/configaroo/releases"
36
36
 
37
37
  [dependency-groups]
38
38
  build = ["build>=1.2.2.post1", "twine>=6.1.0"]
39
- ci = ["mypy>=1.17.1", "pytest>=8.4.1", "rich>=14.1.0", "ruff>=0.12.7", "tomli-w>=1.2.0"]
39
+ ci = ["pytest>=8.4.1", "rich>=14.1.0", "ruff>=0.12.7", "tomli-w>=1.2.0"]
40
40
  dev = [
41
41
  { include-group = "ci" },
42
42
  { include-group = "test" },
43
43
  "bumpver>=2024.1130",
44
44
  "ipython>=8.36.0",
45
45
  "pre-commit>=4.2.0",
46
+ "pyright>=1.1.404",
46
47
  ]
47
48
  test = ["pytest>=8.4.1", "pytest-cov>=6.2.1", "tomli-w>=1.2.0"]
48
49
 
@@ -74,12 +75,18 @@ ignore = [
74
75
  "tests/test_*.py" = ["PLR2004", "S101", "SLF001", "UP018"]
75
76
  "tests/*/test_*.py" = ["S101"]
76
77
 
77
- [tool.mypy]
78
- python_version = "3.11"
79
- strict = true
78
+ [tool.pyright]
79
+ pythonVersion = "3.11"
80
+ typeCheckingMode = "strict"
81
+ verboseOutput = false
82
+ include = ["src/", "tests/", "examples/"]
83
+ venv = ".venv"
84
+
85
+ reportUnknownArgumentType = "none"
86
+ reportUnknownMemberType = "none"
80
87
 
81
88
  [tool.bumpver]
82
- current_version = "v0.4.2"
89
+ current_version = "v0.5.1"
83
90
  version_pattern = "vMAJOR.MINOR.PATCH"
84
91
  commit_message = "bump version {old_version} -> {new_version}"
85
92
  tag_message = "{new_version}"
@@ -20,4 +20,4 @@ __all__ = [
20
20
  "print_configuration",
21
21
  ]
22
22
 
23
- __version__ = "0.4.2"
23
+ __version__ = "0.5.1"
@@ -155,7 +155,7 @@ class Configuration(UserDict[str, Any]):
155
155
  self,
156
156
  model: type[BaseModel],
157
157
  prefix: str = "",
158
- types: type | UnionType = str | bool | int | float,
158
+ types: type | UnionType = str | bool | int | float, # pyright: ignore[reportArgumentType]
159
159
  ) -> Self:
160
160
  """Add environment variables to configuration based on the given model.
161
161
 
@@ -220,26 +220,46 @@ class Configuration(UserDict[str, Any]):
220
220
  }
221
221
 
222
222
 
223
- def print_configuration(config: Configuration | BaseModel, indent: int = 4) -> None:
223
+ def print_configuration(
224
+ config: Configuration | BaseModel, section: str | None = None, indent: int = 4
225
+ ) -> None:
224
226
  """Pretty print a configuration.
225
227
 
226
228
  If rich is installed, then a rich console is used for the printing.
227
229
  """
228
- return _print_dict_as_tree(
229
- config.model_dump() if isinstance(config, BaseModel) else config,
230
- indent=indent,
231
- _print=_get_rich_print(),
230
+ cfg = (
231
+ Configuration(config.model_dump()) if isinstance(config, BaseModel) else config
232
232
  )
233
+ if section is None:
234
+ _print, _escape = _get_rich_print()
235
+ return _print_dict_as_tree(cfg, indent=indent, _print=_print, _escape=_escape)
236
+
237
+ cfg_section = cfg.get(section)
238
+ if cfg_section is None:
239
+ message = f"'{type(cfg).__name__}' has no section '{section}'"
240
+ raise KeyError(message) from None
241
+
242
+ if isinstance(cfg_section, Configuration):
243
+ return print_configuration(cfg_section, indent=indent)
233
244
 
245
+ *_, key = section.split(".")
246
+ return print_configuration(Configuration({key: cfg_section}), indent=indent)
234
247
 
235
- def _get_rich_print() -> Callable[[str], None]: # pragma: no cover
236
- """Initialize a Rich console if Rich is installed, otherwise use built-in print."""
248
+
249
+ def _get_rich_print() -> tuple[
250
+ Callable[[str], None], Callable[[str], str]
251
+ ]: # pragma: no cover
252
+ """Initialize a Rich console if Rich is installed, otherwise use built-in print.
253
+
254
+ Include a function that can be used to escape markup.
255
+ """
237
256
  try:
238
257
  from rich.console import Console # noqa: PLC0415
258
+ from rich.markup import escape # noqa: PLC0415
239
259
 
240
- return Console().print
260
+ return Console().print, escape
241
261
  except ImportError:
242
- return print
262
+ return print, str
243
263
 
244
264
 
245
265
  def _print_dict_as_tree(
@@ -247,6 +267,7 @@ def _print_dict_as_tree(
247
267
  indent: int = 4,
248
268
  current_indent: int = 0,
249
269
  _print: Callable[[str], None] = print,
270
+ _escape: Callable[[str], str] = str,
250
271
  ) -> None:
251
272
  """Print a nested dictionary as a tree."""
252
273
  for key, value in data.items():
@@ -257,9 +278,11 @@ def _print_dict_as_tree(
257
278
  indent=indent,
258
279
  current_indent=current_indent + indent,
259
280
  _print=_print,
281
+ _escape=_escape,
260
282
  )
261
283
  else:
262
- _print(" " * current_indent + f"- {key}: {value!r}")
284
+ escaped_repr = _escape(repr(value))
285
+ _print(" " * current_indent + f"- {key}: {escaped_repr}")
263
286
 
264
287
 
265
288
  def find_pyproject_toml(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.4.2
3
+ Version: 0.5.1
4
4
  Summary: Bouncy handling of configuration files
5
5
  Author-email: Geir Arne Hjelle <geirarne@gmail.com>
6
6
  Maintainer-email: Geir Arne Hjelle <geirarne@gmail.com>
@@ -33,9 +33,9 @@ Dynamic: license-file
33
33
  [![Python versions](https://img.shields.io/pypi/pyversions/configaroo.svg)](https://pypi.org/project/configaroo/)
34
34
  [![License](https://img.shields.io/pypi/l/configaroo.svg)](https://github.com/gahjelle/configaroo/blob/main/LICENSE)
35
35
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
36
- [![Linted](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml)
36
+ [![Linted with Ruff](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/lint.yml)
37
37
  [![Tested with Pytest](https://github.com/gahjelle/configaroo/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/gahjelle/configaroo/actions/workflows/test.yml)
38
- [![Type checked with mypy](https://img.shields.io/badge/type%20checked-mypy-green)](http://mypy-lang.org/)
38
+ [![Type checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
39
39
 
40
40
  Configaroo is a light configuration package for Python that offers the following features:
41
41
 
@@ -127,12 +127,12 @@ def test_find_pyproject_toml() -> None:
127
127
 
128
128
  def test_find_foreign_caller() -> None:
129
129
  """Test that a foreign caller (outside of configaroo) can be identified."""
130
- assert configuration._get_foreign_path() == Path(__file__)
130
+ assert configuration._get_foreign_path() == Path(__file__) # pyright: ignore[reportPrivateUsage]
131
131
 
132
132
 
133
133
  def test_incomplete_formatter() -> None:
134
134
  """Test that the incomplete formatter can handle fields that aren't replaced."""
135
- formatted = configuration._incomplete_format(
135
+ formatted = configuration._incomplete_format( # pyright: ignore[reportPrivateUsage]
136
136
  "{number:5.1f} {non_existent} {string!r} {name}",
137
137
  {"number": 3.14, "string": "platypus", "name": "Geir Arne"},
138
138
  )
@@ -54,3 +54,49 @@ def test_printing_of_dynamic_values(
54
54
  assert "- number: 42" in lines
55
55
  assert "- phrase: 'The meaning of life is 42'" in lines
56
56
  assert " - format: '<level>{level:<8} testing configaroo</level>'" in lines
57
+
58
+
59
+ def test_printing_of_existing_section(
60
+ capsys: pytest.CaptureFixture[str], config: Configuration
61
+ ) -> None:
62
+ """Test that sections can be printed."""
63
+ print_configuration(config, section="paths")
64
+ stdout = capsys.readouterr().out
65
+ lines = stdout.splitlines()
66
+
67
+ assert "- absolute: '/home/configaroo'" in lines
68
+ assert "- number: 42" not in lines
69
+
70
+
71
+ def test_printing_of_nonexisting_section(config: Configuration) -> None:
72
+ """Test that non-existing sections raise an error."""
73
+ with pytest.raises(KeyError):
74
+ print_configuration(config, section="nonexisting")
75
+
76
+
77
+ def test_printing_of_values(
78
+ capsys: pytest.CaptureFixture[str], config: Configuration
79
+ ) -> None:
80
+ """Test that individual values can be printed."""
81
+ print_configuration(config, section="number")
82
+ stdout = capsys.readouterr().out
83
+ lines = stdout.splitlines()
84
+
85
+ assert lines == ["- number: 42"]
86
+
87
+
88
+ def test_printing_of_nested_sections(
89
+ capsys: pytest.CaptureFixture[str], config: Configuration
90
+ ) -> None:
91
+ """Test that nested sections can be printed."""
92
+ print_configuration(config, section="nested.deep")
93
+ stdout = capsys.readouterr().out
94
+ lines = stdout.splitlines()
95
+
96
+ assert lines == ["- sea: 'Marianer'"]
97
+
98
+
99
+ def test_printing_of_rich_markup() -> None:
100
+ """Test that a config value containing malformed Rich markup can be printed."""
101
+ config = Configuration({"markup": "[/]"})
102
+ print_configuration(config)
File without changes
File without changes