configaroo 0.5.0__tar.gz → 0.6.0__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.5.0/src/configaroo.egg-info → configaroo-0.6.0}/PKG-INFO +3 -3
  2. {configaroo-0.5.0 → configaroo-0.6.0}/README.md +2 -2
  3. {configaroo-0.5.0 → configaroo-0.6.0}/pyproject.toml +12 -5
  4. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/__init__.py +1 -1
  5. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/configuration.py +32 -10
  6. {configaroo-0.5.0 → configaroo-0.6.0/src/configaroo.egg-info}/PKG-INFO +3 -3
  7. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_configuration.py +2 -2
  8. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_print.py +30 -0
  9. {configaroo-0.5.0 → configaroo-0.6.0}/LICENSE +0 -0
  10. {configaroo-0.5.0 → configaroo-0.6.0}/setup.cfg +0 -0
  11. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/exceptions.py +0 -0
  12. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/loaders/__init__.py +0 -0
  13. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/loaders/json.py +0 -0
  14. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/loaders/toml.py +0 -0
  15. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo/py.typed +0 -0
  16. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo.egg-info/SOURCES.txt +0 -0
  17. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo.egg-info/dependency_links.txt +0 -0
  18. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo.egg-info/requires.txt +0 -0
  19. {configaroo-0.5.0 → configaroo-0.6.0}/src/configaroo.egg-info/top_level.txt +0 -0
  20. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_dynamic.py +0 -0
  21. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_environment.py +0 -0
  22. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_json.py +0 -0
  23. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_loaders.py +0 -0
  24. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_toml.py +0 -0
  25. {configaroo-0.5.0 → configaroo-0.6.0}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.5.0
3
+ Version: 0.6.0
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.5.0"
89
+ current_version = "v0.6.0"
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.5.0"
23
+ __version__ = "0.6.0"
@@ -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
 
@@ -221,7 +221,11 @@ class Configuration(UserDict[str, Any]):
221
221
 
222
222
 
223
223
  def print_configuration(
224
- config: Configuration | BaseModel, section: str | None = None, indent: int = 4
224
+ config: Configuration | BaseModel,
225
+ section: str | None = None,
226
+ *,
227
+ skip_none: bool = False,
228
+ indent: int = 4,
225
229
  ) -> None:
226
230
  """Pretty print a configuration.
227
231
 
@@ -231,7 +235,10 @@ def print_configuration(
231
235
  Configuration(config.model_dump()) if isinstance(config, BaseModel) else config
232
236
  )
233
237
  if section is None:
234
- return _print_dict_as_tree(cfg, indent=indent, _print=_get_rich_print())
238
+ _print, _escape = _get_rich_print()
239
+ return _print_dict_as_tree(
240
+ cfg, skip_none=skip_none, indent=indent, _print=_print, _escape=_escape
241
+ )
235
242
 
236
243
  cfg_section = cfg.get(section)
237
244
  if cfg_section is None:
@@ -239,30 +246,43 @@ def print_configuration(
239
246
  raise KeyError(message) from None
240
247
 
241
248
  if isinstance(cfg_section, Configuration):
242
- return print_configuration(cfg_section, indent=indent)
249
+ return print_configuration(cfg_section, skip_none=skip_none, indent=indent)
243
250
 
244
251
  *_, key = section.split(".")
245
- return print_configuration(Configuration({key: cfg_section}), indent=indent)
252
+ return print_configuration(
253
+ Configuration({key: cfg_section}), skip_none=skip_none, indent=indent
254
+ )
246
255
 
247
256
 
248
- def _get_rich_print() -> Callable[[str], None]: # pragma: no cover
249
- """Initialize a Rich console if Rich is installed, otherwise use built-in print."""
257
+ def _get_rich_print() -> tuple[
258
+ Callable[[str], None], Callable[[str], str]
259
+ ]: # pragma: no cover
260
+ """Initialize a Rich console if Rich is installed, otherwise use built-in print.
261
+
262
+ Include a function that can be used to escape markup.
263
+ """
250
264
  try:
251
265
  from rich.console import Console # noqa: PLC0415
266
+ from rich.markup import escape # noqa: PLC0415
252
267
 
253
- return Console().print
268
+ return Console().print, escape
254
269
  except ImportError:
255
- return print
270
+ return print, str
256
271
 
257
272
 
258
273
  def _print_dict_as_tree(
259
274
  data: dict[str, Any] | UserDict[str, Any] | Configuration,
275
+ *,
276
+ skip_none: bool = False,
260
277
  indent: int = 4,
261
278
  current_indent: int = 0,
262
279
  _print: Callable[[str], None] = print,
280
+ _escape: Callable[[str], str] = str,
263
281
  ) -> None:
264
282
  """Print a nested dictionary as a tree."""
265
283
  for key, value in data.items():
284
+ if skip_none and value is None:
285
+ continue
266
286
  if isinstance(value, dict | UserDict | Configuration):
267
287
  _print(" " * current_indent + f"- {key}")
268
288
  _print_dict_as_tree(
@@ -270,9 +290,11 @@ def _print_dict_as_tree(
270
290
  indent=indent,
271
291
  current_indent=current_indent + indent,
272
292
  _print=_print,
293
+ _escape=_escape,
273
294
  )
274
295
  else:
275
- _print(" " * current_indent + f"- {key}: {value!r}")
296
+ escaped_repr = _escape(repr(value))
297
+ _print(" " * current_indent + f"- {key}: {escaped_repr}")
276
298
 
277
299
 
278
300
  def find_pyproject_toml(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.5.0
3
+ Version: 0.6.0
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
  )
@@ -94,3 +94,33 @@ def test_printing_of_nested_sections(
94
94
  lines = stdout.splitlines()
95
95
 
96
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)
103
+
104
+
105
+ def test_print_keeping_none(
106
+ capsys: pytest.CaptureFixture[str], config: Configuration
107
+ ) -> None:
108
+ """Test that None-values are kept in printout by default."""
109
+ print_configuration(config | {"none": None})
110
+ stdout = capsys.readouterr().out
111
+ lines = stdout.splitlines()
112
+
113
+ assert "- none: None" in lines
114
+ assert "- number: 42" in lines
115
+
116
+
117
+ def test_print_skipping_none(
118
+ capsys: pytest.CaptureFixture[str], config: Configuration
119
+ ) -> None:
120
+ """Test that None-values are skipped in printout if asked for."""
121
+ print_configuration(config | {"none": None}, skip_none=True)
122
+ stdout = capsys.readouterr().out
123
+ lines = stdout.splitlines()
124
+
125
+ assert "- none: None" not in lines
126
+ assert "- number: 42" in lines
File without changes
File without changes