python-hcl2 8.1.1__tar.gz → 8.1.2__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 (91) hide show
  1. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/CHANGELOG.md +6 -0
  2. {python_hcl2-8.1.1/python_hcl2.egg-info → python_hcl2-8.1.2}/PKG-INFO +1 -1
  3. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/deserializer.py +10 -1
  4. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/hcl2.lark +8 -2
  5. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/reconstructor.py +3 -1
  6. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/literal_rules.py +20 -0
  7. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/strings.py +2 -1
  8. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/tokens.py +3 -0
  9. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/transformer.py +23 -3
  10. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/version.py +3 -3
  11. {python_hcl2-8.1.1 → python_hcl2-8.1.2/python_hcl2.egg-info}/PKG-INFO +1 -1
  12. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/python_hcl2.egg-info/SOURCES.txt +0 -1
  13. python_hcl2-8.1.1/.github/workflows/security.yml +0 -23
  14. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.codacy.yml +0 -0
  15. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.coveragerc +0 -0
  16. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.github/CODEOWNERS +0 -0
  17. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.github/ISSUE_TEMPLATE/hcl2-parsing-error.md +0 -0
  18. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.github/workflows/codeql-analysis.yml +0 -0
  19. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.github/workflows/dependencies_check.yml +0 -0
  20. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.github/workflows/pr_check.yml +0 -0
  21. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.github/workflows/publish.yml +0 -0
  22. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.gitignore +0 -0
  23. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.pre-commit-config.yaml +0 -0
  24. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/.yamllint.yml +0 -0
  25. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/CLAUDE.md +0 -0
  26. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/LICENSE +0 -0
  27. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/MANIFEST.in +0 -0
  28. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/README.md +0 -0
  29. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/bin/check_deps.py +0 -0
  30. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/bin/terraform_test +0 -0
  31. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/cli/__init__.py +0 -0
  32. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/cli/hcl_to_json.py +0 -0
  33. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/cli/helpers.py +0 -0
  34. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/cli/hq.py +0 -0
  35. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/cli/json_to_hcl.py +0 -0
  36. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/docs/01_getting_started.md +0 -0
  37. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/docs/02_querying.md +0 -0
  38. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/docs/03_advanced_api.md +0 -0
  39. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/docs/04_hq.md +0 -0
  40. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/docs/05_hq_examples.md +0 -0
  41. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/docs/06_migrating_to_v8.md +0 -0
  42. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/__init__.py +0 -0
  43. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/__main__.py +0 -0
  44. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/api.py +0 -0
  45. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/builder.py +0 -0
  46. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/const.py +0 -0
  47. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/formatter.py +0 -0
  48. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/parser.py +0 -0
  49. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/postlexer.py +0 -0
  50. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/__init__.py +0 -0
  51. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/_base.py +0 -0
  52. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/attributes.py +0 -0
  53. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/blocks.py +0 -0
  54. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/body.py +0 -0
  55. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/builtins.py +0 -0
  56. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/containers.py +0 -0
  57. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/diff.py +0 -0
  58. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/expressions.py +0 -0
  59. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/for_exprs.py +0 -0
  60. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/functions.py +0 -0
  61. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/introspect.py +0 -0
  62. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/path.py +0 -0
  63. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/pipeline.py +0 -0
  64. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/predicate.py +0 -0
  65. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/resolver.py +0 -0
  66. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/query/safe_eval.py +0 -0
  67. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/__init__.py +0 -0
  68. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/abstract.py +0 -0
  69. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/base.py +0 -0
  70. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/containers.py +0 -0
  71. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/directives.py +0 -0
  72. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/expressions.py +0 -0
  73. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/for_expressions.py +0 -0
  74. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/functions.py +0 -0
  75. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/indexing.py +0 -0
  76. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/rules/whitespace.py +0 -0
  77. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/utils.py +0 -0
  78. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/hcl2/walk.py +0 -0
  79. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/mypy.ini +0 -0
  80. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/pylintrc +0 -0
  81. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/pyproject.toml +0 -0
  82. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/python_hcl2.egg-info/dependency_links.txt +0 -0
  83. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/python_hcl2.egg-info/entry_points.txt +0 -0
  84. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/python_hcl2.egg-info/not-zip-safe +0 -0
  85. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/python_hcl2.egg-info/requires.txt +0 -0
  86. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/python_hcl2.egg-info/top_level.txt +0 -0
  87. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/reports/.gitignore +0 -0
  88. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/requirements.txt +0 -0
  89. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/setup.cfg +0 -0
  90. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/test-requirements.txt +0 -0
  91. {python_hcl2-8.1.1 → python_hcl2-8.1.2}/tox.ini +0 -0
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
9
9
 
10
10
  - Nothing yet.
11
11
 
12
+ ## \[8.1.2\] - 2026-04-10
13
+
14
+ ### Fixed
15
+
16
+ - `true`, `false`, and `null` now serialize to native JSON types instead of strings. ([#293](https://github.com/amplify-education/python-hcl2/issues/293))
17
+
12
18
  ## \[8.1.1\] - 2026-04-07
13
19
 
14
20
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hcl2
3
- Version: 8.1.1
3
+ Version: 8.1.2
4
4
  Summary: A parser for HCL2
5
5
  Author-email: Amplify Education <github@amplify.com>
6
6
  License: MIT
@@ -30,6 +30,7 @@ from hcl2.rules.literal_rules import (
30
30
  IdentifierRule,
31
31
  IntLitRule,
32
32
  FloatLitRule,
33
+ LiteralValueRule,
33
34
  )
34
35
  from hcl2.rules.strings import (
35
36
  StringRule,
@@ -55,6 +56,9 @@ from hcl2.rules.tokens import (
55
56
  HEREDOC_TRIM_TEMPLATE,
56
57
  HEREDOC_TEMPLATE,
57
58
  COLON,
59
+ TRUE,
60
+ FALSE,
61
+ NULL,
58
62
  )
59
63
  from hcl2.transformer import RuleTransformer
60
64
  from hcl2.utils import HEREDOC_TRIM_PATTERN, HEREDOC_PATTERN
@@ -152,7 +156,12 @@ class BaseDeserializer(LarkElementTreeDeserializer):
152
156
  def _deserialize_text(self, value: Any) -> LarkRule:
153
157
  # bool must be checked before int since bool is a subclass of int
154
158
  if isinstance(value, bool):
155
- return self._deserialize_identifier(str(value).lower())
159
+ if value:
160
+ return LiteralValueRule([TRUE()])
161
+ return LiteralValueRule([FALSE()])
162
+
163
+ if value is None:
164
+ return LiteralValueRule([NULL()])
156
165
 
157
166
  if isinstance(value, float):
158
167
  return FloatLitRule([FloatLiteral(value)])
@@ -14,6 +14,10 @@ ELSE : "else"
14
14
  ENDIF : "endif"
15
15
  ENDFOR : "endfor"
16
16
 
17
+ // Literal value keywords
18
+ NULL : "null"
19
+ TRUE : "true"
20
+ FALSE : "false"
17
21
 
18
22
  // Literals
19
23
  NAME : /[a-zA-Z_][a-zA-Z0-9_-]*/
@@ -94,7 +98,7 @@ start : body
94
98
  // Body and basic constructs
95
99
  body : (new_line_or_comment? (attribute | block))* new_line_or_comment?
96
100
  attribute : _attribute_name EQ expression
97
- _attribute_name : identifier | keyword
101
+ _attribute_name : identifier | keyword | literal_value
98
102
  block : identifier (identifier | string)* new_line_or_comment? LBRACE body RBRACE
99
103
 
100
104
  // Whitespace and comments
@@ -103,6 +107,7 @@ new_line_or_comment: ( NL_OR_COMMENT )+
103
107
  // Basic literals and identifiers
104
108
  identifier : NAME
105
109
  keyword: IN | FOR | IF | FOR_EACH | ELSE | ENDIF | ENDFOR
110
+ literal_value: TRUE | FALSE | NULL
106
111
  int_lit: INT_LITERAL
107
112
  float_lit: FLOAT_LITERAL
108
113
  string: DBLQUOTE string_part* DBLQUOTE
@@ -189,6 +194,7 @@ expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR
189
194
  | tuple
190
195
  | object
191
196
  | identifier
197
+ | literal_value
192
198
  | function_call
193
199
  | heredoc_template
194
200
  | heredoc_template_trim
@@ -223,7 +229,7 @@ full_splat_expr_term : expr_term full_splat
223
229
  ?index : braces_index | short_index
224
230
  braces_index : LSQB new_line_or_comment? expression new_line_or_comment? RSQB
225
231
  short_index : DOT INT_LITERAL
226
- get_attr : DOT identifier
232
+ get_attr : DOT (identifier | literal_value)
227
233
  attr_splat : ATTR_SPLAT (get_attr | index)*
228
234
  full_splat : FULL_SPLAT_START (get_attr | index)*
229
235
 
@@ -16,7 +16,7 @@ from hcl2.rules.directives import (
16
16
  TemplateEndforRule,
17
17
  )
18
18
  from hcl2.rules.for_expressions import ForIntroRule, ForTupleExprRule, ForObjectExprRule
19
- from hcl2.rules.literal_rules import IdentifierRule
19
+ from hcl2.rules.literal_rules import IdentifierRule, LiteralValueRule
20
20
  from hcl2.rules.strings import StringRule
21
21
  from hcl2.rules.expressions import (
22
22
  ExprTermRule,
@@ -228,9 +228,11 @@ class HCLReconstructor:
228
228
  if rule_name in [
229
229
  StringRule.lark_name(),
230
230
  IdentifierRule.lark_name(),
231
+ LiteralValueRule.lark_name(),
231
232
  ] and self._last_rule_name in [
232
233
  StringRule.lark_name(),
233
234
  IdentifierRule.lark_name(),
235
+ LiteralValueRule.lark_name(),
234
236
  ]:
235
237
  return True
236
238
 
@@ -33,6 +33,26 @@ class KeywordRule(TokenRule):
33
33
  return "keyword"
34
34
 
35
35
 
36
+ class LiteralValueRule(TokenRule):
37
+ """Rule for HCL2 literal value keywords (true, false, null)."""
38
+
39
+ _SERIALIZE_MAP = {"true": True, "false": False, "null": None}
40
+
41
+ @staticmethod
42
+ def lark_name() -> str:
43
+ """Return the grammar rule name."""
44
+ return "literal_value"
45
+
46
+ def serialize(
47
+ self, options=SerializationOptions(), context=SerializationContext()
48
+ ) -> Any:
49
+ """Serialize to Python True, False, or None."""
50
+ value = self.token.value
51
+ if context.inside_dollar_string:
52
+ return str(value)
53
+ return self._SERIALIZE_MAP.get(str(value), str(value))
54
+
55
+
36
56
  class IdentifierRule(TokenRule):
37
57
  """Rule for HCL2 identifiers."""
38
58
 
@@ -48,7 +48,8 @@ class InterpolationRule(LarkRule):
48
48
  self, options=SerializationOptions(), context=SerializationContext()
49
49
  ) -> Any:
50
50
  """Serialize to ${expression} string."""
51
- return to_dollar_string(self.expression.serialize(options, context))
51
+ with context.modify(inside_dollar_string=True):
52
+ return to_dollar_string(self.expression.serialize(options, context))
52
53
 
53
54
 
54
55
  class StringPartRule(LarkRule):
@@ -125,6 +125,9 @@ FOR_OBJECT_ARROW = StaticStringToken[("FOR_OBJECT_ARROW", "=>")] # type: ignore
125
125
  ELSE = StaticStringToken[("ELSE", "else")] # type: ignore
126
126
  ENDIF = StaticStringToken[("ENDIF", "endif")] # type: ignore
127
127
  ENDFOR = StaticStringToken[("ENDFOR", "endfor")] # type: ignore
128
+ TRUE = StaticStringToken[("TRUE", "true")] # type: ignore
129
+ FALSE = StaticStringToken[("FALSE", "false")] # type: ignore
130
+ NULL = StaticStringToken[("NULL", "null")] # type: ignore
128
131
 
129
132
  # pylint: enable=invalid-name
130
133
 
@@ -48,6 +48,7 @@ from hcl2.rules.literal_rules import (
48
48
  IdentifierRule,
49
49
  BinaryOperatorRule,
50
50
  KeywordRule,
51
+ LiteralValueRule,
51
52
  )
52
53
  from hcl2.rules.strings import (
53
54
  InterpolationRule,
@@ -133,8 +134,9 @@ class RuleTransformer(Transformer):
133
134
 
134
135
  @v_args(meta=True)
135
136
  def attribute(self, meta: Meta, args) -> AttributeRule:
136
- # _attribute_name is flattened, so args[0] may be KeywordRule or IdentifierRule
137
- if isinstance(args[0], KeywordRule):
137
+ # _attribute_name is flattened, so args[0] may be KeywordRule,
138
+ # LiteralValueRule, or IdentifierRule
139
+ if isinstance(args[0], (KeywordRule, LiteralValueRule)):
138
140
  args[0] = IdentifierRule([NAME(args[0].token.value)], meta)
139
141
  return AttributeRule(args, meta)
140
142
 
@@ -154,6 +156,10 @@ class RuleTransformer(Transformer):
154
156
  def keyword(self, meta: Meta, args) -> KeywordRule:
155
157
  return KeywordRule(args, meta)
156
158
 
159
+ @v_args(meta=True)
160
+ def literal_value(self, meta: Meta, args) -> LiteralValueRule:
161
+ return LiteralValueRule(args, meta)
162
+
157
163
  @v_args(meta=True)
158
164
  def int_lit(self, meta: Meta, args) -> IntLitRule:
159
165
  return IntLitRule(args, meta)
@@ -333,8 +339,18 @@ class RuleTransformer(Transformer):
333
339
  if isinstance(expr, ExprTermRule) and len(expr.children) == 5:
334
340
  inner = expr.children[2] # position 2 in [None, None, inner, None, None]
335
341
  if isinstance(
336
- inner, (IdentifierRule, StringRule, IntLitRule, FloatLitRule)
342
+ inner,
343
+ (
344
+ IdentifierRule,
345
+ StringRule,
346
+ IntLitRule,
347
+ FloatLitRule,
348
+ LiteralValueRule,
349
+ ),
337
350
  ):
351
+ # Convert literal_value to identifier for dict key compatibility
352
+ if isinstance(inner, LiteralValueRule):
353
+ inner = IdentifierRule([NAME(inner.token.value)], meta)
338
354
  return ObjectElemKeyRule([inner], meta)
339
355
  # Any other expression (parenthesized or bare)
340
356
  return ObjectElemKeyExpressionRule([expr], meta)
@@ -361,6 +377,10 @@ class RuleTransformer(Transformer):
361
377
 
362
378
  @v_args(meta=True)
363
379
  def get_attr(self, meta: Meta, args) -> GetAttrRule:
380
+ # Convert literal_value (true/false/null) to identifier in attr access
381
+ if len(args) >= 2 and isinstance(args[1], LiteralValueRule):
382
+ args = list(args)
383
+ args[1] = IdentifierRule([NAME(args[1].token.value)], meta)
364
384
  return GetAttrRule(args, meta)
365
385
 
366
386
  @v_args(meta=True)
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '8.1.1'
22
- __version_tuple__ = version_tuple = (8, 1, 1)
21
+ __version__ = version = '8.1.2'
22
+ __version_tuple__ = version_tuple = (8, 1, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g472f03318'
24
+ __commit_id__ = commit_id = 'ga602753ce'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hcl2
3
- Version: 8.1.1
3
+ Version: 8.1.2
4
4
  Summary: A parser for HCL2
5
5
  Author-email: Amplify Education <github@amplify.com>
6
6
  License: MIT
@@ -20,7 +20,6 @@ tox.ini
20
20
  .github/workflows/dependencies_check.yml
21
21
  .github/workflows/pr_check.yml
22
22
  .github/workflows/publish.yml
23
- .github/workflows/security.yml
24
23
  bin/check_deps.py
25
24
  bin/terraform_test
26
25
  cli/__init__.py
@@ -1,23 +0,0 @@
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 }}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes