python-hcl2 7.3.1__tar.gz → 8.0.0rc2__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 (78) hide show
  1. python_hcl2-8.0.0rc2/.coveragerc +15 -0
  2. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.github/ISSUE_TEMPLATE/hcl2-parsing-error.md +9 -5
  3. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.github/workflows/codeql-analysis.yml +1 -1
  4. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.github/workflows/dependencies_check.yml +1 -1
  5. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.github/workflows/pr_check.yml +2 -2
  6. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.github/workflows/publish.yml +2 -2
  7. python_hcl2-8.0.0rc2/.github/workflows/security.yml +23 -0
  8. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.pre-commit-config.yaml +1 -0
  9. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/CHANGELOG.md +31 -0
  10. python_hcl2-8.0.0rc2/CLAUDE.md +144 -0
  11. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/PKG-INFO +53 -27
  12. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/README.md +50 -23
  13. python_hcl2-8.0.0rc2/cli/hcl_to_json.py +138 -0
  14. python_hcl2-8.0.0rc2/cli/helpers.py +96 -0
  15. python_hcl2-8.0.0rc2/cli/json_to_hcl.py +136 -0
  16. python_hcl2-8.0.0rc2/docs/usage.md +306 -0
  17. python_hcl2-8.0.0rc2/hcl2/__init__.py +28 -0
  18. python_hcl2-8.0.0rc2/hcl2/__main__.py +5 -0
  19. python_hcl2-8.0.0rc2/hcl2/api.py +222 -0
  20. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/hcl2/builder.py +7 -10
  21. python_hcl2-8.0.0rc2/hcl2/const.py +5 -0
  22. python_hcl2-8.0.0rc2/hcl2/deserializer.py +375 -0
  23. python_hcl2-8.0.0rc2/hcl2/formatter.py +332 -0
  24. python_hcl2-8.0.0rc2/hcl2/hcl2.lark +206 -0
  25. python_hcl2-8.0.0rc2/hcl2/parser.py +23 -0
  26. python_hcl2-8.0.0rc2/hcl2/postlexer.py +79 -0
  27. python_hcl2-8.0.0rc2/hcl2/reconstructor.py +295 -0
  28. python_hcl2-8.0.0rc2/hcl2/rules/__init__.py +0 -0
  29. python_hcl2-8.0.0rc2/hcl2/rules/abstract.py +139 -0
  30. python_hcl2-8.0.0rc2/hcl2/rules/base.py +172 -0
  31. python_hcl2-8.0.0rc2/hcl2/rules/containers.py +229 -0
  32. python_hcl2-8.0.0rc2/hcl2/rules/expressions.py +300 -0
  33. python_hcl2-8.0.0rc2/hcl2/rules/for_expressions.py +321 -0
  34. python_hcl2-8.0.0rc2/hcl2/rules/functions.py +113 -0
  35. python_hcl2-8.0.0rc2/hcl2/rules/indexing.py +293 -0
  36. python_hcl2-8.0.0rc2/hcl2/rules/literal_rules.py +86 -0
  37. python_hcl2-8.0.0rc2/hcl2/rules/strings.py +187 -0
  38. python_hcl2-8.0.0rc2/hcl2/rules/tokens.py +150 -0
  39. python_hcl2-8.0.0rc2/hcl2/rules/whitespace.py +87 -0
  40. python_hcl2-8.0.0rc2/hcl2/transformer.py +306 -0
  41. python_hcl2-8.0.0rc2/hcl2/utils.py +94 -0
  42. python_hcl2-8.0.0rc2/hcl2/version.py +34 -0
  43. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/pylintrc +1 -1
  44. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/pyproject.toml +5 -5
  45. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/python_hcl2.egg-info/PKG-INFO +53 -27
  46. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/python_hcl2.egg-info/SOURCES.txt +23 -2
  47. python_hcl2-8.0.0rc2/python_hcl2.egg-info/entry_points.txt +3 -0
  48. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/python_hcl2.egg-info/top_level.txt +1 -0
  49. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/tox.ini +2 -3
  50. python_hcl2-7.3.1/.coveragerc +0 -9
  51. python_hcl2-7.3.1/hcl2/__init__.py +0 -18
  52. python_hcl2-7.3.1/hcl2/__main__.py +0 -106
  53. python_hcl2-7.3.1/hcl2/api.py +0 -67
  54. python_hcl2-7.3.1/hcl2/const.py +0 -4
  55. python_hcl2-7.3.1/hcl2/hcl2.lark +0 -108
  56. python_hcl2-7.3.1/hcl2/parser.py +0 -42
  57. python_hcl2-7.3.1/hcl2/reconstructor.py +0 -734
  58. python_hcl2-7.3.1/hcl2/transformer.py +0 -399
  59. python_hcl2-7.3.1/hcl2/version.py +0 -21
  60. python_hcl2-7.3.1/python_hcl2.egg-info/entry_points.txt +0 -2
  61. python_hcl2-7.3.1/tree-to-hcl2-reconstruction.md +0 -248
  62. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.codacy.yml +0 -0
  63. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.github/CODEOWNERS +0 -0
  64. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.gitignore +0 -0
  65. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/.yamllint.yml +0 -0
  66. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/LICENSE +0 -0
  67. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/MANIFEST.in +0 -0
  68. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/bin/check_deps.py +0 -0
  69. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/bin/terraform_test +0 -0
  70. /python_hcl2-7.3.1/hcl2/py.typed → /python_hcl2-8.0.0rc2/cli/__init__.py +0 -0
  71. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/mypy.ini +0 -0
  72. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/python_hcl2.egg-info/dependency_links.txt +0 -0
  73. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/python_hcl2.egg-info/not-zip-safe +0 -0
  74. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/python_hcl2.egg-info/requires.txt +0 -0
  75. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/reports/.gitignore +0 -0
  76. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/requirements.txt +0 -0
  77. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/setup.cfg +0 -0
  78. {python_hcl2-7.3.1 → python_hcl2-8.0.0rc2}/test-requirements.txt +0 -0
@@ -0,0 +1,15 @@
1
+ [run]
2
+ branch = true
3
+ omit =
4
+ hcl2/lark_parser.py
5
+ hcl2/version.py
6
+ hcl2/__main__.py
7
+ hcl2/__init__.py
8
+ hcl2/rules/__init__.py
9
+ cli/__init__.py
10
+
11
+ [report]
12
+ show_missing = true
13
+ fail_under = 95
14
+ exclude_lines =
15
+ raise NotImplementedError
@@ -1,27 +1,31 @@
1
- ---
1
+ ______________________________________________________________________
2
+
2
3
  name: HCL2 parsing error
3
4
  about: Template for reporting a bug related to parsing HCL2 code
4
5
  title: ''
5
6
  labels: bug
6
7
  assignees: kkozik-amplify
7
8
 
8
- ---
9
+ ______________________________________________________________________
9
10
 
10
11
  **Describe the bug**
11
12
 
12
13
  A clear and concise description of what the bug is.
13
14
 
14
15
  **Software:**
15
- - OS: [macOS / Windows / Linux]
16
- - Python version (e.g. 3.9.21)
17
- - python-hcl2 version (e.g. 7.0.0)
16
+
17
+ - OS: \[macOS / Windows / Linux\]
18
+ - Python version (e.g. 3.9.21)
19
+ - python-hcl2 version (e.g. 7.0.0)
18
20
 
19
21
  **Snippet of HCL2 code causing the unexpected behaviour:**
22
+
20
23
  ```terraform
21
24
  locals {
22
25
  foo = "bar"
23
26
  }
24
27
  ```
28
+
25
29
  **Expected behavior**
26
30
 
27
31
  A clear and concise description of what you expected to happen, e.g. python dictionary or JSON you expected to receive as a result of parsing.
@@ -13,7 +13,7 @@ on:
13
13
  jobs:
14
14
  analyse:
15
15
  name: Analyse
16
- runs-on: ubuntu-latest
16
+ runs-on: github-hosted-static-ip
17
17
 
18
18
  steps:
19
19
  - name: Checkout repository
@@ -14,7 +14,7 @@ on:
14
14
  jobs:
15
15
  test:
16
16
  name: Check dependencies sync between pyproject.toml and requirements.txt
17
- runs-on: ubuntu-22.04
17
+ runs-on: github-hosted-static-ip
18
18
  steps:
19
19
  - uses: actions/checkout@master
20
20
  - name: Set up Python 3.13
@@ -10,10 +10,10 @@ on:
10
10
  jobs:
11
11
  test:
12
12
  name: Check code against linter/unit tests
13
- runs-on: ubuntu-22.04
13
+ runs-on: github-hosted-static-ip
14
14
  strategy:
15
15
  matrix:
16
- python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
16
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
17
17
  steps:
18
18
  - uses: actions/checkout@master
19
19
  - name: Set up Python ${{ matrix.python-version }}
@@ -2,12 +2,12 @@
2
2
  name: Publish
3
3
  on:
4
4
  release:
5
- types: [released]
5
+ types: [published]
6
6
 
7
7
  jobs:
8
8
  build-publish:
9
9
  name: Build and publish Python distributions
10
- runs-on: ubuntu-22.04
10
+ runs-on: github-hosted-static-ip
11
11
  steps:
12
12
  - uses: actions/checkout@master
13
13
  - name: Set up Python
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: Security Review
3
+
4
+ permissions:
5
+ pull-requests: write # Needed for leaving PR comments
6
+ contents: read
7
+
8
+ on:
9
+ pull_request:
10
+
11
+ jobs:
12
+ security:
13
+ runs-on: github-hosted-static-ip
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ ref: ${{ github.event.pull_request.head.sha || github.sha }}
18
+ fetch-depth: 2
19
+
20
+ - uses: anthropics/claude-code-security-review@main
21
+ with:
22
+ comment-pr: true
23
+ claude-api-key: ${{ secrets.ANTHROPIC_CLAUDE_API_KEY }}
@@ -6,6 +6,7 @@ repos:
6
6
  rev: v4.3.0
7
7
  hooks:
8
8
  - id: trailing-whitespace
9
+ exclude: ^test/integration/(hcl2_reconstructed|specialized)/
9
10
  - id: end-of-file-fixer
10
11
  - id: check-added-large-files
11
12
  - id: no-commit-to-branch # Prevent commits directly to master
@@ -9,6 +9,37 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
9
9
 
10
10
  - Nothing yet.
11
11
 
12
+ ## \[8.0.0\] - rc2
13
+
14
+ ### Added
15
+
16
+ - Full architecture overhaul: bidirectional HCL2 ↔ JSON pipeline with typed rule classes. ([#203](https://github.com/amplify-education/python-hcl2/pull/203))
17
+ - add function tuples round-trip test suite ([#268](https://github.com/amplify-education/python-hcl2/pull/268))
18
+ - Add postlexer to support multiline binary operators and ternary expressions ([#270](https://github.com/amplify-education/python-hcl2/pull/270))
19
+ - more robust whitespace handling in reconstruction ([#271](https://github.com/amplify-education/python-hcl2/pull/271))
20
+ - SerializationOptions - add an option to strip string quotes in dict/JSON output ([#272](https://github.com/amplify-education/python-hcl2/pull/272))
21
+ - CLAUDE.md ([#260](https://github.com/amplify-education/python-hcl2/pull/260))
22
+
23
+ ### Fixed
24
+
25
+ - Ternary with strings parse error ([#55](https://github.com/amplify-education/python-hcl2/issues/55))
26
+ - "No terminal matches '|' in the current parser context" when parsing multi-line conditional ([#142](https://github.com/amplify-education/python-hcl2/issues/142))
27
+ - reverse_transform not working with object-type variables ([#231](https://github.com/amplify-education/python-hcl2/issues/231))
28
+ - reverse_transform not handling nested functions ([#235](https://github.com/amplify-education/python-hcl2/issues/235))
29
+ - `writes` omits quotes around map keys with `/` ([#236](https://github.com/amplify-education/python-hcl2/issues/236))
30
+ - Operator precedence bug ([#248](https://github.com/amplify-education/python-hcl2/issues/248))
31
+ - Empty string dictionary keys can't be parsed twice ([#249](https://github.com/amplify-education/python-hcl2/issues/249))
32
+ - jsonencode not deserialized correctly ([#250](https://github.com/amplify-education/python-hcl2/issues/250))
33
+ - Literal string "string" incorrectly quoted ([#251](https://github.com/amplify-education/python-hcl2/issues/251))
34
+ - Interpolation literals added to locals/variables in maps ([#252](https://github.com/amplify-education/python-hcl2/issues/252))
35
+ - Object literal expression can't be serialized ([#253](https://github.com/amplify-education/python-hcl2/issues/253))
36
+ - Heredocs should interpret backslash literally ([#262](https://github.com/amplify-education/python-hcl2/issues/262))
37
+ - Parsing a multi-line multi-conditional expression causes exception - Unexpected token Token('QMARK', '?') ([#269](https://github.com/amplify-education/python-hcl2/issues/269))
38
+
39
+ ### Changed
40
+
41
+ - Updated package metadata: development status, dropped Python 3.7 support. ([#263](https://github.com/amplify-education/python-hcl2/pull/263))
42
+
12
43
  ## \[7.3.1\] - 2025-07-24
13
44
 
14
45
  ### Fixed
@@ -0,0 +1,144 @@
1
+ # HCL2 Parser — CLAUDE.md
2
+
3
+ ## Pipeline
4
+
5
+ ```
6
+ Forward: HCL2 Text → [PostLexer] → Lark Parse Tree → LarkElement Tree → Python Dict/JSON
7
+ Reverse: Python Dict/JSON → LarkElement Tree → Lark Tree → HCL2 Text
8
+ Direct: HCL2 Text → [PostLexer] → Lark Parse Tree → LarkElement Tree → Lark Tree → HCL2 Text
9
+ ```
10
+
11
+ The **Direct** pipeline (`parse_to_tree` → `transform` → `to_lark` → `reconstruct`) skips serialization to dict, so all IR nodes (including `NewLineOrCommentRule` nodes for whitespace/comments) directly influence the reconstructed output. Any information discarded before the IR is lost in this pipeline.
12
+
13
+ ## Module Map
14
+
15
+ | Module | Role |
16
+ |---|---|
17
+ | `hcl2/hcl2.lark` | Lark grammar definition |
18
+ | `hcl2/api.py` | Public API (`load/loads/dump/dumps` + intermediate stages) |
19
+ | `hcl2/postlexer.py` | Token stream transforms between lexer and parser |
20
+ | `hcl2/parser.py` | Lark parser factory with caching |
21
+ | `hcl2/transformer.py` | Lark parse tree → LarkElement tree |
22
+ | `hcl2/deserializer.py` | Python dict → LarkElement tree |
23
+ | `hcl2/formatter.py` | Whitespace alignment and spacing on LarkElement trees |
24
+ | `hcl2/reconstructor.py` | LarkElement tree → HCL2 text via Lark |
25
+ | `hcl2/builder.py` | Programmatic HCL document construction |
26
+ | `hcl2/utils.py` | `SerializationOptions`, `SerializationContext`, string helpers |
27
+ | `hcl2/const.py` | Constants: `IS_BLOCK`, `COMMENTS_KEY`, `INLINE_COMMENTS_KEY` |
28
+ | `cli/helpers.py` | File/directory/stdin conversion helpers |
29
+ | `cli/hcl_to_json.py` | `hcl2tojson` entry point |
30
+ | `cli/json_to_hcl.py` | `jsontohcl2` entry point |
31
+
32
+ `hcl2/__main__.py` is a thin wrapper that imports `cli.hcl_to_json:main`.
33
+
34
+ ### Rules (one class per grammar rule)
35
+
36
+ | File | Domain |
37
+ |---|---|
38
+ | `rules/abstract.py` | `LarkElement`, `LarkRule`, `LarkToken` base classes |
39
+ | `rules/tokens.py` | `StringToken` (cached factory), `StaticStringToken`, punctuation constants |
40
+ | `rules/base.py` | `StartRule`, `BodyRule`, `BlockRule`, `AttributeRule` |
41
+ | `rules/containers.py` | `TupleRule`, `ObjectRule`, `ObjectElemRule`, `ObjectElemKeyRule` |
42
+ | `rules/expressions.py` | `ExprTermRule`, `BinaryOpRule`, `UnaryOpRule`, `ConditionalRule` |
43
+ | `rules/literal_rules.py` | `IntLitRule`, `FloatLitRule`, `IdentifierRule`, `KeywordRule` |
44
+ | `rules/strings.py` | `StringRule`, `InterpolationRule`, `HeredocTemplateRule` |
45
+ | `rules/functions.py` | `FunctionCallRule`, `ArgumentsRule` |
46
+ | `rules/indexing.py` | `GetAttrRule`, `SqbIndexRule`, splat rules |
47
+ | `rules/for_expressions.py` | `ForTupleExprRule`, `ForObjectExprRule`, `ForIntroRule`, `ForCondRule` |
48
+ | `rules/whitespace.py` | `NewLineOrCommentRule`, `InlineCommentMixIn` |
49
+
50
+ ## Public API (`api.py`)
51
+
52
+ Follows the `json` module convention. All option parameters are keyword-only.
53
+
54
+ - `load/loads` — HCL2 text → Python dict
55
+ - `dump/dumps` — Python dict → HCL2 text
56
+ - Intermediate stages: `parse/parses`, `parse_to_tree/parses_to_tree`, `transform`, `serialize`, `from_dict`, `from_json`, `reconstruct`
57
+
58
+ ### Option Dataclasses
59
+
60
+ **`SerializationOptions`** (LarkElement → dict):
61
+ `with_comments`, `with_meta`, `wrap_objects`, `wrap_tuples`, `explicit_blocks`, `preserve_heredocs`, `force_operation_parentheses`, `preserve_scientific_notation`
62
+
63
+ **`DeserializerOptions`** (dict → LarkElement):
64
+ `heredocs_to_strings`, `strings_to_heredocs`, `object_elements_colon`, `object_elements_trailing_comma`
65
+
66
+ **`FormatterOptions`** (whitespace/alignment):
67
+ `indent_length`, `open_empty_blocks`, `open_empty_objects`, `open_empty_tuples`, `vertically_align_attributes`, `vertically_align_object_elements`
68
+
69
+ ## CLI
70
+
71
+ Console scripts defined in `pyproject.toml`. Each uses argparse flags that map directly to the option dataclass fields above.
72
+
73
+ ```
74
+ hcl2tojson --json-indent 2 --with-meta file.tf
75
+ jsontohcl2 --indent 4 --no-align file.json
76
+ ```
77
+
78
+ Add new options as `parser.add_argument()` calls in the relevant entry point module.
79
+
80
+ ## PostLexer (`postlexer.py`)
81
+
82
+ Lark's `postlex` parameter accepts a single object with a `process(stream)` method that transforms the token stream between the lexer and LALR parser. The `PostLexer` class is designed for extensibility: each transformation is a private method that accepts and yields tokens, and `process()` chains them together.
83
+
84
+ Current passes:
85
+
86
+ - `_merge_newlines_into_operators`
87
+
88
+ To add a new pass: create a private method with the same `(self, stream) -> generator` signature, and add a `yield from` call in `process()`.
89
+
90
+ ## Hard Rules
91
+
92
+ These are project-specific constraints that must not be violated:
93
+
94
+ 1. **Always use the LarkElement IR.** Never transform directly from Lark parse tree to Python dict or vice versa.
95
+ 1. **Block vs object distinction.** Use `__is_block__` markers (`const.IS_BLOCK`) to preserve semantic intent during round-trips. The deserializer must distinguish blocks from regular objects.
96
+ 1. **Bidirectional completeness.** Every serialization path must have a corresponding deserialization path. Test round-trip integrity: Parse → Serialize → Deserialize → Serialize produces identical results.
97
+ 1. **One grammar rule = one `LarkRule` class.** Each class implements `lark_name()`, typed property accessors, `serialize()`, and declares `_children_layout: Tuple[...]` (annotation only, no assignment) to document child structure.
98
+ 1. **Token caching.** Use the `StringToken` factory in `rules/tokens.py` — never create token instances directly.
99
+ 1. **Interpolation context.** `${...}` generation depends on nesting depth — always pass and respect `SerializationContext`.
100
+ 1. **Update both directions.** When adding language features, update transformer.py, deserializer.py, formatter.py and reconstructor.py.
101
+
102
+ ## Adding a New Language Construct
103
+
104
+ 1. Add grammar rules to `hcl2.lark`
105
+ 1. If the new construct creates LALR ambiguities with `NL_OR_COMMENT`, add a postlexer pass in `postlexer.py`
106
+ 1. Create rule class(es) in the appropriate `rules/` file
107
+ 1. Add transformer method(s) in `transformer.py`
108
+ 1. Implement `serialize()` in the rule class
109
+ 1. Update `deserializer.py`, `formatter.py` and `reconstructor.py` for round-trip support
110
+
111
+ ## Testing
112
+
113
+ Framework: `unittest.TestCase` (not pytest).
114
+
115
+ ```
116
+ python -m unittest discover -s test -p "test_*.py" -v
117
+ ```
118
+
119
+ **Unit tests** (`test/unit/`): instantiate rule objects directly (no parsing).
120
+
121
+ - `rules/` — one file per rules module
122
+ - `cli/` — one file per CLI module
123
+ - `test_*.py` — tests for corresponding files from `hcl2/` directory
124
+
125
+ Use concrete stubs when testing ABCs (e.g., `StubExpression(ExpressionRule)`).
126
+
127
+ **Integration tests** (`test/integration/`): full-pipeline tests with golden files.
128
+
129
+ - `test_round_trip.py` — iterates over all suites in `hcl2_original/`, tests HCL→JSON, JSON→JSON, JSON→HCL, and full round-trip
130
+ - `test_specialized.py` — feature-specific tests with golden files in `specialized/`
131
+
132
+ Always run round-trip full test suite after any modification.
133
+
134
+ ## Pre-commit Checks
135
+
136
+ Hooks are defined in `.pre-commit-config.yaml` (includes black, mypy, pylint, and others). All changed files must pass these checks before committing. When writing or modifying code:
137
+
138
+ - Format Python with **black** (Python 3.8 target).
139
+ - Ensure **mypy** and **pylint** pass. Pylint config is in `pylintrc`, scoped to `hcl2/` and `test/`.
140
+ - End files with a newline; strip trailing whitespace (except under `test/integration/(hcl2_reconstructed|specialized)/`).
141
+
142
+ ## Keeping Docs Current
143
+
144
+ Update this file when architecture, modules, API surface, or testing conventions change. Also update `README.md` and `docs/usage.md` when changes affect the public API, CLI flags, or option fields.
@@ -1,25 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hcl2
3
- Version: 7.3.1
3
+ Version: 8.0.0rc2
4
4
  Summary: A parser for HCL2
5
5
  Author-email: Amplify Education <github@amplify.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/amplify-education/python-hcl2
8
- Classifier: Development Status :: 4 - Beta
8
+ Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.7
16
15
  Classifier: Programming Language :: Python :: 3.8
17
16
  Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
- Requires-Python: >=3.7.0
21
+ Requires-Python: >=3.8.0
23
22
  Description-Content-Type: text/markdown
24
23
  License-File: LICENSE
25
24
  Requires-Dist: lark<2.0,>=1.1.5
@@ -27,7 +26,6 @@ Requires-Dist: regex>=2024.4.16
27
26
  Dynamic: license-file
28
27
 
29
28
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2e2015f9297346cbaa788c46ab957827)](https://app.codacy.com/gh/amplify-education/python-hcl2/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
30
- [![Build Status](https://travis-ci.org/amplify-education/python-hcl2.svg?branch=master)](https://travis-ci.org/amplify-education/python-hcl2)
31
29
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/amplify-education/python-hcl2/master/LICENSE)
32
30
  [![PyPI](https://img.shields.io/pypi/v/python-hcl2.svg)](https://pypi.org/project/python-hcl2/)
33
31
  [![Python Versions](https://img.shields.io/pypi/pyversions/python-hcl2.svg)](https://pypi.python.org/pypi/python-hcl2)
@@ -52,7 +50,7 @@ Learn more at <https://www.amplify.com>
52
50
 
53
51
  ### Prerequisites
54
52
 
55
- python-hcl2 requires Python 3.7 or higher to run.
53
+ python-hcl2 requires Python 3.8 or higher to run.
56
54
 
57
55
  ### Installing
58
56
 
@@ -64,19 +62,58 @@ pip3 install python-hcl2
64
62
 
65
63
  ### Usage
66
64
 
65
+ **HCL2 to Python dict:**
66
+
67
67
  ```python
68
68
  import hcl2
69
- with open('foo.tf', 'r') as file:
70
- dict = hcl2.load(file)
69
+
70
+ with open("main.tf") as f:
71
+ data = hcl2.load(f)
71
72
  ```
72
73
 
73
- ### Parse Tree to HCL2 reconstruction
74
+ **Python dict to HCL2:**
75
+
76
+ ```python
77
+ import hcl2
78
+
79
+ hcl_string = hcl2.dumps(data)
80
+
81
+ with open("output.tf", "w") as f:
82
+ hcl2.dump(data, f)
83
+ ```
74
84
 
75
- With version 6.x the possibility of HCL2 reconstruction from the Lark Parse Tree and Python dictionaries directly was introduced.
85
+ **Building HCL from scratch:**
76
86
 
77
- Documentation and an example of manipulating Lark Parse Tree and reconstructing it back into valid HCL2 can be found in [tree-to-hcl2-reconstruction.md](https://github.com/amplify-education/python-hcl2/blob/main/tree-to-hcl2-reconstruction.md) file.
87
+ ```python
88
+ import hcl2
89
+
90
+ doc = hcl2.Builder()
91
+ res = doc.block("resource", labels=["aws_instance", "web"], ami="abc-123", instance_type="t2.micro")
92
+ res.block("tags", Name="HelloWorld")
93
+
94
+ hcl_string = hcl2.dumps(doc.build())
95
+ ```
96
+
97
+ For the full API reference, option dataclasses, intermediate pipeline stages, and more examples
98
+ see [docs/usage.md](https://github.com/amplify-education/python-hcl2/blob/main/docs/usage.md).
99
+
100
+ ### CLI Tools
101
+
102
+ python-hcl2 ships two command-line converters:
103
+
104
+ ```sh
105
+ # HCL2 → JSON
106
+ hcl2tojson main.tf # prints JSON to stdout
107
+ hcl2tojson main.tf output.json # writes to file
108
+ hcl2tojson terraform/ output/ # converts a directory
109
+
110
+ # JSON → HCL2
111
+ jsontohcl2 output.json # prints HCL2 to stdout
112
+ jsontohcl2 output.json main.tf # writes to file
113
+ jsontohcl2 output/ terraform/ # converts a directory
114
+ ```
78
115
 
79
- More details about reconstruction implementation can be found in PRs #169 and #177.
116
+ Both commands accept `-` as PATH to read from stdin. Run `hcl2tojson --help` or `jsontohcl2 --help` for the full list of flags.
80
117
 
81
118
  ## Building From Source
82
119
 
@@ -89,7 +126,7 @@ Running `tox` will automatically execute linters as well as the unit tests.
89
126
 
90
127
  You can also run them individually with the `-e` argument.
91
128
 
92
- For example, `tox -e py37-unit` will run the unit tests for python 3.7
129
+ For example, `tox -e py310-unit` will run the unit tests for python 3.10
93
130
 
94
131
  To see all the available options, run `tox -l`.
95
132
 
@@ -109,21 +146,10 @@ You can reach us at <mailto:github@amplify.com>
109
146
  We welcome pull requests! For your pull request to be accepted smoothly, we suggest that you:
110
147
 
111
148
  - For any sizable change, first open a GitHub issue to discuss your idea.
112
- - Create a pull request. Explain why you want to make the change and what its for.
149
+ - Create a pull request. Explain why you want to make the change and what it's for.
113
150
 
114
- Well try to answer any PRs promptly.
151
+ We'll try to answer any PR's promptly.
115
152
 
116
153
  ## Limitations
117
154
 
118
- ### Using inline expression as an object key
119
-
120
- - Object key can be an expression as long as it is wrapped in parentheses:
121
- ```terraform
122
- locals {
123
- foo = "bar"
124
- baz = {
125
- (format("key_prefix_%s", local.foo)) : "value"
126
- # format("key_prefix_%s", local.foo) : "value" this will fail
127
- }
128
- }
129
- ```
155
+ None that are known.
@@ -1,5 +1,4 @@
1
1
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2e2015f9297346cbaa788c46ab957827)](https://app.codacy.com/gh/amplify-education/python-hcl2/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
2
- [![Build Status](https://travis-ci.org/amplify-education/python-hcl2.svg?branch=master)](https://travis-ci.org/amplify-education/python-hcl2)
3
2
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/amplify-education/python-hcl2/master/LICENSE)
4
3
  [![PyPI](https://img.shields.io/pypi/v/python-hcl2.svg)](https://pypi.org/project/python-hcl2/)
5
4
  [![Python Versions](https://img.shields.io/pypi/pyversions/python-hcl2.svg)](https://pypi.python.org/pypi/python-hcl2)
@@ -24,7 +23,7 @@ Learn more at <https://www.amplify.com>
24
23
 
25
24
  ### Prerequisites
26
25
 
27
- python-hcl2 requires Python 3.7 or higher to run.
26
+ python-hcl2 requires Python 3.8 or higher to run.
28
27
 
29
28
  ### Installing
30
29
 
@@ -36,19 +35,58 @@ pip3 install python-hcl2
36
35
 
37
36
  ### Usage
38
37
 
38
+ **HCL2 to Python dict:**
39
+
39
40
  ```python
40
41
  import hcl2
41
- with open('foo.tf', 'r') as file:
42
- dict = hcl2.load(file)
42
+
43
+ with open("main.tf") as f:
44
+ data = hcl2.load(f)
43
45
  ```
44
46
 
45
- ### Parse Tree to HCL2 reconstruction
47
+ **Python dict to HCL2:**
48
+
49
+ ```python
50
+ import hcl2
51
+
52
+ hcl_string = hcl2.dumps(data)
53
+
54
+ with open("output.tf", "w") as f:
55
+ hcl2.dump(data, f)
56
+ ```
46
57
 
47
- With version 6.x the possibility of HCL2 reconstruction from the Lark Parse Tree and Python dictionaries directly was introduced.
58
+ **Building HCL from scratch:**
48
59
 
49
- Documentation and an example of manipulating Lark Parse Tree and reconstructing it back into valid HCL2 can be found in [tree-to-hcl2-reconstruction.md](https://github.com/amplify-education/python-hcl2/blob/main/tree-to-hcl2-reconstruction.md) file.
60
+ ```python
61
+ import hcl2
62
+
63
+ doc = hcl2.Builder()
64
+ res = doc.block("resource", labels=["aws_instance", "web"], ami="abc-123", instance_type="t2.micro")
65
+ res.block("tags", Name="HelloWorld")
66
+
67
+ hcl_string = hcl2.dumps(doc.build())
68
+ ```
69
+
70
+ For the full API reference, option dataclasses, intermediate pipeline stages, and more examples
71
+ see [docs/usage.md](https://github.com/amplify-education/python-hcl2/blob/main/docs/usage.md).
72
+
73
+ ### CLI Tools
74
+
75
+ python-hcl2 ships two command-line converters:
76
+
77
+ ```sh
78
+ # HCL2 → JSON
79
+ hcl2tojson main.tf # prints JSON to stdout
80
+ hcl2tojson main.tf output.json # writes to file
81
+ hcl2tojson terraform/ output/ # converts a directory
82
+
83
+ # JSON → HCL2
84
+ jsontohcl2 output.json # prints HCL2 to stdout
85
+ jsontohcl2 output.json main.tf # writes to file
86
+ jsontohcl2 output/ terraform/ # converts a directory
87
+ ```
50
88
 
51
- More details about reconstruction implementation can be found in PRs #169 and #177.
89
+ Both commands accept `-` as PATH to read from stdin. Run `hcl2tojson --help` or `jsontohcl2 --help` for the full list of flags.
52
90
 
53
91
  ## Building From Source
54
92
 
@@ -61,7 +99,7 @@ Running `tox` will automatically execute linters as well as the unit tests.
61
99
 
62
100
  You can also run them individually with the `-e` argument.
63
101
 
64
- For example, `tox -e py37-unit` will run the unit tests for python 3.7
102
+ For example, `tox -e py310-unit` will run the unit tests for python 3.10
65
103
 
66
104
  To see all the available options, run `tox -l`.
67
105
 
@@ -81,21 +119,10 @@ You can reach us at <mailto:github@amplify.com>
81
119
  We welcome pull requests! For your pull request to be accepted smoothly, we suggest that you:
82
120
 
83
121
  - For any sizable change, first open a GitHub issue to discuss your idea.
84
- - Create a pull request. Explain why you want to make the change and what its for.
122
+ - Create a pull request. Explain why you want to make the change and what it's for.
85
123
 
86
- Well try to answer any PRs promptly.
124
+ We'll try to answer any PR's promptly.
87
125
 
88
126
  ## Limitations
89
127
 
90
- ### Using inline expression as an object key
91
-
92
- - Object key can be an expression as long as it is wrapped in parentheses:
93
- ```terraform
94
- locals {
95
- foo = "bar"
96
- baz = {
97
- (format("key_prefix_%s", local.foo)) : "value"
98
- # format("key_prefix_%s", local.foo) : "value" this will fail
99
- }
100
- }
101
- ```
128
+ None that are known.