humans do make some errors, so we should show it to them, so that it can be fixed
fromhuman_errorsimportjson_dumpimportorjsontry:
withopen("config.json", "r") asfile:
config=orjson.loads(file.read())
exceptorjson.JSONDecodeErrorasexc:
json_dump(exc, "config.json")Output (error):
--> C:\Users\<user>\absolute\path\to\config.json:19:5
17 │ "path": "$DESKTOP"
18 │ }
╭╴19 │ {
│ │ ↑
│ 20 │ "name": "Pictures",
│ 21 │ "path": "$PICTURES"
╰────❯ unexpected characterif you want to use tomllib, python >= 3.14 must be used so that the message and line + column numbers can be extracted.
fromhuman_errorsimporttoml_dumpimporttomltry:
withopen("pyproject.toml", "r") asfile:
config=toml.loads(file.read())
excepttoml.TomlDecodeErrorasexc:
toml_dump(exc, "pyproject.toml")Output (error):
--> C:\Users\<user>\path\to\pyproject.toml:9:26
7 │ { name = "<name>", email = "<email>" }
8 │ ]
╭╴ 9 │ requires-python = ">=3.12│ │ ↑│ 10 │ dependencies = [│ 11 │ "rich>=14.2.0",╰────❯ Unbalanced quotesfromhuman_errorsimportyaml_dumpimportyamltry:
withopen("config.yaml", "r") asfile:
config=yaml.safe_load(file.read())
exceptyaml.YAMLErrorasexc:
yaml_dump(exc, "config.yaml")Output (error):
--> C:\Users\<user>\absolute\path\to\config.yaml:5:3
3 │ name: "John"
4 │ age: 30
╭╴5 │ email: john@example.com
│ │ ↑
│ 6 │ - item1
│ 7 │ - item2
╰────❯ mapping values are not allowed hereFor custom error handling or any file-based errors not covered by the built-in renderers:
fromhuman_errors.base_rendererimportdumpdefvalidate_config(file_path: str):
withopen(file_path, "r") asf:
forline_num, lineinenumerate(f, start=1):
if"TODO"inline:
col=line.index("TODO") +1dump(
doc_path=file_path,
cause="TODO found in production config",
line_number=line_num,
column_number=col,
context=3,
extra=[
"Production configs should not contain TODO items",
"Please replace with actual values or remove this entry"
]
)
exit(1)Output (error):
--> C:\Users\<user>\absolute\path\to\config.py:15:9
12 │ DATABASE_HOST = "localhost"
13 │ DATABASE_PORT = 5432
14 │
╭╴15 │ API_KEY = "TODO: add production key"
│ │ ↑
│ 16 │
│ 17 │ CACHE_ENABLED = True
│ 18 │ CACHE_TTL = 3600
╰─────❯ TODO found in production config
╭───────────────────────────────────────────────────────────╮
│ Production configs should not contain TODO items │
├───────────────────────────────────────────────────────────┤
│ Please replace with actual values or remove this entry │
╰───────────────────────────────────────────────────────────╯if you dont like human-error's default styling, a miette like version is also available
╭─[/path/to/file.json:2:19]
1 │ {
2 │ "name": "Alice",,
· ┬
· ╰─❯ Expecting property name enclosed in double quotes
3 │ "age": 30
╰────A command-line interface is provided to parse files and render errors:
uvx human-errors path/to/file.[json|toml|yaml|yml] [--renderer default|miette]- Automatically detects format from file extension
- On parse errors, uses human_errors' renderer for neater output
- Optional
--rendererselects the output style
Example:
uvx human-errors examples/bad.jsonany extra data format must be in an extra, and also available in the all group
any contributions must pre-lint with ruff and ty
uv run ruff check --unsafe-fixes --fix
uv run ty checkadding support for pytest is also fine