Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.local.*

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down Expand Up @@ -52,3 +54,5 @@ docs/_build/

# PyBuilder
target/
.idea/
.eggs/
14 changes: 6 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
dist: xenial
dist: noble
language: python
python:
- 2.7
- 3.4
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9
- 3.10
- 3.11
- 3.12
- 3.13
- 3.14
before_install: pip install --upgrade setuptools
install: pip install tox tox-travis coveralls
before_script: if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then tox -e flake8; fi
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog


#


# Version 0.4.0
Major overhaul of the library.

* Upgrade of the build system and directory structure to use pyproject.toml
* Update of the dependencies
* Add support for Python 3.10+
* Remove support for Python 2.7


# Version 0.3.61

* fix(tox): remove old EOLed python 3.x versions, added new python versions (@pierresouchay) [#330]
Expand Down
96 changes: 96 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

pyhocon is a Python implementation of the HOCON (Human-Optimized Config Object Notation) parser. It parses HOCON configuration files into Python data structures and can convert to JSON, YAML, properties, and HOCON formats.

HOCON spec: https://github.com/typesafehub/config/blob/master/HOCON.md

## Commands

### Testing
```bash
# Run all tests
pytest tests/

# Run a specific test file
pytest tests/test_config_parser.py

# Run a specific test
pytest tests/test_config_parser.py::TestConfigParser::test_parse_simple_value

# Run with coverage
coverage run --source=pyhocon -m pytest tests/
coverage report -m
```

### Linting
```bash
flake8 pyhocon tests setup.py.old
```

### Tox (multi-environment testing)
```bash
tox # Run all environments
tox -e flake8 # Run flake8 only
tox -e py312 # Run tests on Python 3.12
```

### CLI Tool
```bash
# Convert HOCON to JSON
pyhocon -i input.conf -f json -o output.json
cat input.conf | pyhocon -f json

# Other formats: json, yaml, properties, hocon
# Use -c for compact output (nested single-value dicts as a.b.c = 1)
```

## Architecture

### Core Modules

- **config_parser.py** - Main parsing engine using pyparsing library
- `ConfigFactory` - Public API for parsing (parse_file, parse_string, parse_URL, from_dict)
- `ConfigParser` - Internal parser with HOCON grammar rules

- **config_tree.py** - Data structures
- `ConfigTree` - Hierarchical config storage (extends OrderedDict), supports dot notation access (`config['a.b.c']`)
- `ConfigList` - HOCON arrays
- `ConfigValues` - Concatenated values (handles array/string/dict merging)
- `ConfigSubstitution` - Represents `${var}` and `${?var}` substitutions

- **converter.py** - `HOCONConverter` with to_json, to_yaml, to_properties, to_hocon methods

- **period_parser.py / period_serializer.py** - Duration parsing (e.g., "5 days", "10 seconds")

- **tool.py** - CLI entry point

### Parsing Flow

1. `ConfigFactory.parse_*()` receives input
2. `ConfigParser.parse()` applies pyparsing grammar rules
3. Produces `ConfigTree`/`ConfigList` with unresolved `ConfigSubstitution` tokens
4. `resolve_substitutions()` replaces `${var}` references from config or environment variables
5. Returns resolved `ConfigTree`

### Key Features

- Substitutions: `${key}` (required) and `${?key}` (optional, fallback to env vars)
- Includes: `include "file.conf"`, `include url("http://...")`, `include required(file("..."))`, glob patterns
- Value access: `config['a.b.c']` or `config['a']['b']['c']` or `config.get_string('a.b.c')`
- Type-safe getters: `get_string()`, `get_int()`, `get_float()`, `get_bool()`, `get_list()`, `get_config()`

## Dependencies

- **pyparsing** (>=2, <4) - Grammar parsing
- **python-dateutil** (>=2.8.0, optional) - For months/years in duration parsing

## Test Dependencies

- pytest
- mock
- python-dateutil
- coveralls (for CI coverage reporting)
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ It is available on pypi so you can install it as follows:
The parsed config can be seen as a nested dictionary (with types automatically inferred) where values can be accessed using normal
dictionary getter (e.g., `conf['a']['b']` or using paths like `conf['a.b']`) or via the methods `get`, `get_int` (throws an exception
if it is not an int), `get_string`, `get_list`, `get_float`, `get_bool`, `get_config`.

```python
from pyhocon import ConfigFactory

Expand All @@ -37,7 +38,7 @@ same_host = conf['databases']['mysql.host']
port = conf['databases.mysql.port']
username = conf['databases']['mysql']['username']
password = conf.get_config('databases')['mysql.password']
password = conf.get('databases.mysql.password', 'default_password') # use default value if key not found
password = conf.get('databases.mysql.password', 'default_password') # use default value if key not found
```

## Example of HOCON file
Expand Down
38 changes: 38 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[build-system]
requires = ["setuptools>=80.10.2", "wheel"]

[project]
name = "pyhocon_up"
version = "0.4.0"
description = "HOCON parser for Python"
readme = "README.md"
license = "Apache-2.0"
authors = [
{name = "Robert Rapplean", email = "mythobeast@gmail.com"}
]
keywords = ["hocon", "parser"]
classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
requires-python = ">=3.10"
dependencies = [
"pyparsing>=3,<4",
]

[project.optional-dependencies]
duration = ["python-dateutil>=2.8.0"]
test = ["pytest", "pytest-cov", "mock==5.2.0"]

[project.urls]
Homepage = "http://github.com/mythobeast/pyhocon/"

[project.scripts]
pyhocon = "pyhocon.tool:main"

2 changes: 1 addition & 1 deletion setup.cfg → setup.cfg.old
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[flake8]
ignore =
ignore = E1,W1
max-line-length = 160
statistics = True
count = True
Expand Down
8 changes: 3 additions & 5 deletions setup.py → setup.py.old
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def run_tests(self):
author_email='francois.dangngoc@gmail.com',
url='http://github.com/chimpler/pyhocon/',
classifiers=[
'License :: OSI Approved :: Apache Software License',
'Topic :: Software Development :: Libraries :: Python Modules',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
Expand All @@ -54,18 +53,17 @@ def run_tests(self):
],
install_requires=[
'pyparsing~=2.0;python_version<"3.0"',
'pyparsing>=2,<4;python_version>="3.0"',
'pyparsing>=3,<4;python_version>="3.0"',
],
extras_require={
'Duration': ['python-dateutil>=2.8.0']
'Duration': ['python-dateutil>=2.8.0'],
'test': ['pytest', 'mock==3.0.5']
},
tests_require=['pytest', 'mock==3.0.5'],
entry_points={
'console_scripts': [
'pyhocon=pyhocon.tool:main'
]
},
test_suite='tests',
cmdclass={
'test': PyTestCommand
}
Expand Down
File renamed without changes.
Loading