• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aas-core-works / aas-core-codegen / 23051946462

13 Mar 2026 12:59PM UTC coverage: 83.657% (+1.2%) from 82.428%
23051946462

push

github

web-flow
Turn on coveralls (#596)

The site coveralls.io was down so we had to turn off the coverage
upload temporarily.

30831 of 36854 relevant lines covered (83.66%)

3.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.36
/aas_core_codegen/python/lib/_generate_constants.py
1
"""Generate the Python constants corresponding to the constants of the meta-model."""
2
import io
4✔
3
import textwrap
4✔
4
from typing import (
4✔
5
    Optional,
6
    List,
7
    Tuple,
8
)
9

10
from icontract import ensure
4✔
11

12
from aas_core_codegen import intermediate
4✔
13
from aas_core_codegen.common import (
4✔
14
    Error,
15
    assert_never,
16
    Stripped,
17
    indent_but_first_line,
18
    Identifier,
19
)
20
from aas_core_codegen.python import (
4✔
21
    common as python_common,
22
    naming as python_naming,
23
    description as python_description,
24
)
25
from aas_core_codegen.python.common import (
4✔
26
    INDENT as I,
27
)
28

29

30
# region Generation
31

32

33
def _generate_documentation_comment_for_constant(
4✔
34
    description: intermediate.DescriptionOfConstant, context: python_description.Context
35
) -> Tuple[Optional[Stripped], Optional[List[Error]]]:
36
    """Generate the docstring for the given constant."""
37
    text, errors = python_description.generate_summary_remarks(
4✔
38
        description=description, context=context
39
    )
40

41
    if errors is not None:
4✔
42
        return None, errors
×
43

44
    assert text is not None
4✔
45

46
    return python_description.documentation_comment(text), None
4✔
47

48

49
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
4✔
50
def _generate_constant_primitive(
4✔
51
    constant: intermediate.ConstantPrimitive,
52
    qualified_module_name: python_common.QualifiedModuleName,
53
) -> Tuple[Optional[Stripped], Optional[Error]]:
54
    """Generate the definition of a constant primitive."""
55
    writer = io.StringIO()
×
56

57
    if constant.description is not None:
×
58
        docstring, docstring_errors = _generate_documentation_comment_for_constant(
×
59
            description=constant.description,
60
            context=python_description.Context(
61
                qualified_module_name=qualified_module_name,
62
                module=Identifier("constants"),
63
                cls_or_enum=None,
64
            ),
65
        )
66
        if docstring_errors is not None:
×
67
            return None, Error(
×
68
                constant.parsed.node,
69
                f"Failed to generate the documentation comment for {constant.name!r}",
70
                docstring_errors,
71
            )
72

73
        assert docstring is not None
×
74
        writer.write(docstring)
×
75
        writer.write("\n")
×
76

77
    constant_name = python_naming.constant_name(constant.name)
×
78

79
    if constant.a_type is intermediate.PrimitiveType.BOOL:
×
80
        literal = "True" if constant.value else "False"
×
81

82
        writer.write(f"{constant_name}: bool = {literal}")
×
83

84
    elif constant.a_type is intermediate.PrimitiveType.INT:
×
85
        literal = str(constant.value)
×
86

87
        writer.write(f"{constant_name}: int = {literal}")
×
88

89
    elif constant.a_type is intermediate.PrimitiveType.FLOAT:
×
90
        # NOTE (mristin, 2022-09-28):
91
        # We assume that the float constants are not meant to be all to precise.
92
        # Therefore, we use a string representation here. However, beware that we
93
        # might have to use a more precise representation in the future if the spec
94
        # change.
95
        literal = str(constant.value)
×
96

97
        writer.write(f"{constant_name}: float = {literal}")
×
98

99
    elif constant.a_type is intermediate.PrimitiveType.STR:
×
100
        assert isinstance(constant.value, str)
×
101
        literal = python_common.string_literal(constant.value)
×
102

103
        writer.write(f"{constant_name}: str = {literal}")
×
104

105
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
106
        assert isinstance(constant.value, bytearray)
×
107

108
        literal, _ = python_common.bytes_literal(value=constant.value)
×
109

110
        writer.write(
×
111
            f"""\
112
{constant_name}: bytes = (
113
{I}{indent_but_first_line(literal, I)}
114
)"""
115
        )
116

117
    else:
118
        assert_never(constant.a_type)
×
119

120
    return Stripped(writer.getvalue()), None
×
121

122

123
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
4✔
124
def _generate_constant_set_of_primitives(
4✔
125
    constant: intermediate.ConstantSetOfPrimitives,
126
    qualified_module_name: python_common.QualifiedModuleName,
127
) -> Tuple[Optional[Stripped], Optional[Error]]:
128
    """Generate the definition of a constant set of primitives."""
129
    writer = io.StringIO()
4✔
130

131
    if constant.description is not None:
4✔
132
        docstring, docstring_errors = _generate_documentation_comment_for_constant(
4✔
133
            description=constant.description,
134
            context=python_description.Context(
135
                qualified_module_name=qualified_module_name,
136
                module=Identifier("constants"),
137
                cls_or_enum=None,
138
            ),
139
        )
140
        if docstring_errors is not None:
4✔
141
            return None, Error(
×
142
                constant.parsed.node,
143
                f"Failed to generate the documentation comment for {constant.name!r}",
144
                docstring_errors,
145
            )
146

147
        assert docstring is not None
4✔
148
        writer.write(docstring)
4✔
149
        writer.write("\n")
4✔
150

151
    constant_name = python_naming.constant_name(constant.name)
4✔
152

153
    if constant.a_type is intermediate.PrimitiveType.BOOL:
4✔
154
        writer.write(
×
155
            f"""\
156
{constant_name}: Set[bool] = {{
157
"""
158
        )
159

160
        for i, literal in enumerate(constant.literals):
×
161
            writer.write(textwrap.indent("True" if literal.value else "False", I))
×
162

163
            if i < len(constant.literals) - 1:
×
164
                writer.write(",\n")
×
165
            else:
166
                writer.write("\n")
×
167

168
        writer.write("}")
×
169

170
    elif constant.a_type is intermediate.PrimitiveType.INT:
4✔
171
        writer.write(
×
172
            f"""\
173
{constant_name}: Set[int] = {{
174
"""
175
        )
176

177
        for i, literal in enumerate(constant.literals):
×
178
            writer.write(textwrap.indent(str(literal.value), I))
×
179

180
            if i < len(constant.literals) - 1:
×
181
                writer.write(",\n")
×
182
            else:
183
                writer.write("\n")
×
184

185
        writer.write("}")
×
186

187
    elif constant.a_type is intermediate.PrimitiveType.FLOAT:
4✔
188
        # NOTE (mristin, 2022-07-06):
189
        # We assume that the float constants are not meant to be all to precise.
190
        # Therefore, we use a string representation here. However, beware that we
191
        # might have to use a more precise representation in the future if the spec
192
        # change.
193

194
        writer.write(
×
195
            f"""\
196
{constant_name}: Set[float] = {{
197
"""
198
        )
199

200
        for i, literal in enumerate(constant.literals):
×
201
            writer.write(textwrap.indent(str(literal.value), I))
×
202

203
            if i < len(constant.literals) - 1:
×
204
                writer.write(",\n")
×
205
            else:
206
                writer.write("\n")
×
207

208
        writer.write("}")
×
209

210
    elif constant.a_type is intermediate.PrimitiveType.STR:
4✔
211
        writer.write(
4✔
212
            f"""\
213
{constant_name}: Set[str] = {{
214
"""
215
        )
216

217
        for i, literal in enumerate(constant.literals):
4✔
218
            assert isinstance(literal.value, str)
4✔
219

220
            writer.write(
4✔
221
                textwrap.indent(python_common.string_literal(literal.value), I)
222
            )
223

224
            if i < len(constant.literals) - 1:
4✔
225
                writer.write(",\n")
4✔
226
            else:
227
                writer.write("\n")
4✔
228

229
        writer.write("}")
4✔
230

231
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
232
        writer.write(
×
233
            f"""\
234
{constant_name}: Set[bytes] = {{
235
"""
236
        )
237

238
        for i, literal in enumerate(constant.literals):
×
239
            assert isinstance(literal.value, bytearray)
×
240

241
            literal_in_code, _ = python_common.bytes_literal(bytes(literal.value))
×
242

243
            writer.write(textwrap.indent(literal_in_code, I))
×
244

245
            if i < len(constant.literals) - 1:
×
246
                writer.write(",\n")
×
247
            else:
248
                writer.write("\n")
×
249

250
        writer.write("}")
×
251

252
    else:
253
        assert_never(constant.a_type)
×
254

255
    return Stripped(writer.getvalue()), None
4✔
256

257

258
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
4✔
259
def _generate_constant_set_of_enumeration_literals(
4✔
260
    constant: intermediate.ConstantSetOfEnumerationLiterals,
261
    qualified_module_name: python_common.QualifiedModuleName,
262
) -> Tuple[Optional[Stripped], Optional[Error]]:
263
    """Generate the definition of a constant set of enumeration literals."""
264
    writer = io.StringIO()
4✔
265

266
    if constant.description is not None:
4✔
267
        docstring, docstring_errors = _generate_documentation_comment_for_constant(
4✔
268
            description=constant.description,
269
            context=python_description.Context(
270
                qualified_module_name=qualified_module_name,
271
                module=Identifier("constants"),
272
                cls_or_enum=None,
273
            ),
274
        )
275
        if docstring_errors is not None:
4✔
276
            return None, Error(
×
277
                constant.parsed.node,
278
                f"Failed to generate the documentation comment for {constant.name!r}",
279
                docstring_errors,
280
            )
281

282
        assert docstring is not None
4✔
283
        writer.write(docstring)
4✔
284
        writer.write("\n")
4✔
285

286
    constant_name = python_naming.constant_name(constant.name)
4✔
287
    enum_name = python_naming.enum_name(constant.enumeration.name)
4✔
288

289
    writer.write(
4✔
290
        f"""\
291
{constant_name}: Set[aas_types.{enum_name}] = {{
292
"""
293
    )
294

295
    for i, literal in enumerate(constant.literals):
4✔
296
        literal_name = python_naming.enum_literal_name(literal.name)
4✔
297

298
        writer.write(textwrap.indent(f"aas_types.{enum_name}.{literal_name}", I))
4✔
299

300
        if i < len(constant.literals) - 1:
4✔
301
            writer.write(",\n")
4✔
302
        else:
303
            writer.write("\n")
4✔
304

305
    writer.write("}")
4✔
306

307
    return Stripped(writer.getvalue()), None
4✔
308

309

310
# fmt: off
311
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
4✔
312
@ensure(
4✔
313
    lambda result:
314
    not (result[0] is not None) or result[0].endswith('\n'),
315
    "Trailing newline mandatory for valid end-of-files"
316
)
317
# fmt: on
318
def generate(
4✔
319
    symbol_table: intermediate.SymbolTable,
320
    qualified_module_name: python_common.QualifiedModuleName,
321
) -> Tuple[Optional[str], Optional[List[Error]]]:
322
    """
323
    Generate the Python code of the constants based on the symbol table.
324

325
    The ``qualified_module_name`` indicates the fully-qualified name of the base module.
326
    """
327
    errors = []  # type: List[Error]
4✔
328

329
    blocks = [
4✔
330
        Stripped('"""Provide constant values of the meta-model."""'),
331
        python_common.WARNING,
332
        Stripped(
333
            f"""\
334
from typing import Set
335

336
import {qualified_module_name}.types as aas_types"""
337
        ),
338
    ]  # type: List[Stripped]
339

340
    for constant in symbol_table.constants:
4✔
341
        block: Optional[Stripped]
342
        error: Optional[Error]
343

344
        if isinstance(constant, intermediate.ConstantPrimitive):
4✔
345
            block, error = _generate_constant_primitive(
×
346
                constant=constant, qualified_module_name=qualified_module_name
347
            )
348
        elif isinstance(constant, intermediate.ConstantSetOfPrimitives):
4✔
349
            block, error = _generate_constant_set_of_primitives(
4✔
350
                constant=constant, qualified_module_name=qualified_module_name
351
            )
352
        elif isinstance(constant, intermediate.ConstantSetOfEnumerationLiterals):
4✔
353
            block, error = _generate_constant_set_of_enumeration_literals(
4✔
354
                constant=constant, qualified_module_name=qualified_module_name
355
            )
356
        else:
357
            assert_never(constant)
×
358

359
        if error is not None:
4✔
360
            errors.append(error)
×
361
            continue
×
362

363
        assert block is not None
4✔
364
        blocks.append(block)
4✔
365

366
    if len(errors) > 0:
4✔
367
        return None, errors
×
368

369
    blocks.append(python_common.WARNING)
4✔
370

371
    writer = io.StringIO()
4✔
372
    for i, block in enumerate(blocks):
4✔
373
        if i > 0:
4✔
374
            writer.write("\n\n")
4✔
375

376
        writer.write(block)
4✔
377

378
    writer.write("\n")
4✔
379

380
    return writer.getvalue(), None
4✔
381

382

383
# endregion
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc