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

aas-core-works / aas-core-codegen / 17360913018

31 Aug 2025 06:35PM UTC coverage: 82.105% (+0.1%) from 82.003%
17360913018

push

github

web-flow
Upgrade pylint to 3.3.8 (#551)

We upgrade pylint to the latest version so that we can still check the
code with the newest Python 3.13.

28501 of 34713 relevant lines covered (82.1%)

3.28 hits per line

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

54.36
/aas_core_codegen/python/constants/_generate.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
    aas_module: 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
                aas_module=aas_module, module=Identifier("constants"), cls_or_enum=None
62
            ),
63
        )
64
        if docstring_errors is not None:
×
65
            return None, Error(
×
66
                constant.parsed.node,
67
                f"Failed to generate the documentation comment for {constant.name!r}",
68
                docstring_errors,
69
            )
70

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

75
    constant_name = python_naming.constant_name(constant.name)
×
76

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

80
        writer.write(f"{constant_name}: bool = {literal}")
×
81

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

85
        writer.write(f"{constant_name}: int = {literal}")
×
86

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

95
        writer.write(f"{constant_name}: float = {literal}")
×
96

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

101
        writer.write(f"{constant_name}: str = {literal}")
×
102

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

106
        literal, _ = python_common.bytes_literal(value=constant.value)
×
107

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

115
    else:
116
        assert_never(constant.a_type)
×
117

118
    return Stripped(writer.getvalue()), None
×
119

120

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

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

143
        assert docstring is not None
4✔
144
        writer.write(docstring)
4✔
145
        writer.write("\n")
4✔
146

147
    constant_name = python_naming.constant_name(constant.name)
4✔
148

149
    if constant.a_type is intermediate.PrimitiveType.BOOL:
4✔
150
        writer.write(
×
151
            f"""\
152
{constant_name}: Set[bool] = {{
153
"""
154
        )
155

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

159
            if i < len(constant.literals) - 1:
×
160
                writer.write(",\n")
×
161
            else:
162
                writer.write("\n")
×
163

164
        writer.write("}")
×
165

166
    elif constant.a_type is intermediate.PrimitiveType.INT:
4✔
167
        writer.write(
×
168
            f"""\
169
{constant_name}: Set[int] = {{
170
"""
171
        )
172

173
        for i, literal in enumerate(constant.literals):
×
174
            writer.write(textwrap.indent(str(literal.value), I))
×
175

176
            if i < len(constant.literals) - 1:
×
177
                writer.write(",\n")
×
178
            else:
179
                writer.write("\n")
×
180

181
        writer.write("}")
×
182

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

190
        writer.write(
×
191
            f"""\
192
{constant_name}: Set[float] = {{
193
"""
194
        )
195

196
        for i, literal in enumerate(constant.literals):
×
197
            writer.write(textwrap.indent(str(literal.value), I))
×
198

199
            if i < len(constant.literals) - 1:
×
200
                writer.write(",\n")
×
201
            else:
202
                writer.write("\n")
×
203

204
        writer.write("}")
×
205

206
    elif constant.a_type is intermediate.PrimitiveType.STR:
4✔
207
        writer.write(
4✔
208
            f"""\
209
{constant_name}: Set[str] = {{
210
"""
211
        )
212

213
        for i, literal in enumerate(constant.literals):
4✔
214
            assert isinstance(literal.value, str)
4✔
215

216
            writer.write(
4✔
217
                textwrap.indent(python_common.string_literal(literal.value), I)
218
            )
219

220
            if i < len(constant.literals) - 1:
4✔
221
                writer.write(",\n")
4✔
222
            else:
223
                writer.write("\n")
4✔
224

225
        writer.write("}")
4✔
226

227
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
228
        writer.write(
×
229
            f"""\
230
{constant_name}: Set[bytes] = {{
231
"""
232
        )
233

234
        for i, literal in enumerate(constant.literals):
×
235
            assert isinstance(literal.value, bytearray)
×
236

237
            literal_in_code, _ = python_common.bytes_literal(bytes(literal.value))
×
238

239
            writer.write(textwrap.indent(literal_in_code, I))
×
240

241
            if i < len(constant.literals) - 1:
×
242
                writer.write(",\n")
×
243
            else:
244
                writer.write("\n")
×
245

246
        writer.write("}")
×
247

248
    else:
249
        assert_never(constant.a_type)
×
250

251
    return Stripped(writer.getvalue()), None
4✔
252

253

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

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

276
        assert docstring is not None
4✔
277
        writer.write(docstring)
4✔
278
        writer.write("\n")
4✔
279

280
    constant_name = python_naming.constant_name(constant.name)
4✔
281
    enum_name = python_naming.enum_name(constant.enumeration.name)
4✔
282

283
    writer.write(
4✔
284
        f"""\
285
{constant_name}: Set[aas_types.{enum_name}] = {{
286
"""
287
    )
288

289
    for i, literal in enumerate(constant.literals):
4✔
290
        literal_name = python_naming.enum_literal_name(literal.name)
4✔
291

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

294
        if i < len(constant.literals) - 1:
4✔
295
            writer.write(",\n")
4✔
296
        else:
297
            writer.write("\n")
4✔
298

299
    writer.write("}")
4✔
300

301
    return Stripped(writer.getvalue()), None
4✔
302

303

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

319
    The ``aas_module`` indicates the fully-qualified name of the base module.
320
    """
321
    errors = []  # type: List[Error]
4✔
322

323
    blocks = [
4✔
324
        Stripped('"""Provide constant values of the meta-model."""'),
325
        python_common.WARNING,
326
        Stripped(
327
            f"""\
328
from typing import Set
329

330
import {aas_module}.types as aas_types"""
331
        ),
332
    ]  # type: List[Stripped]
333

334
    for constant in symbol_table.constants:
4✔
335
        block: Optional[Stripped]
336
        error: Optional[Error]
337

338
        if isinstance(constant, intermediate.ConstantPrimitive):
4✔
339
            block, error = _generate_constant_primitive(
×
340
                constant=constant, aas_module=aas_module
341
            )
342
        elif isinstance(constant, intermediate.ConstantSetOfPrimitives):
4✔
343
            block, error = _generate_constant_set_of_primitives(
4✔
344
                constant=constant, aas_module=aas_module
345
            )
346
        elif isinstance(constant, intermediate.ConstantSetOfEnumerationLiterals):
4✔
347
            block, error = _generate_constant_set_of_enumeration_literals(
4✔
348
                constant=constant, aas_module=aas_module
349
            )
350
        else:
351
            assert_never(constant)
×
352

353
        if error is not None:
4✔
354
            errors.append(error)
×
355
            continue
×
356

357
        assert block is not None
4✔
358
        blocks.append(block)
4✔
359

360
    if len(errors) > 0:
4✔
361
        return None, errors
×
362

363
    blocks.append(python_common.WARNING)
4✔
364

365
    writer = io.StringIO()
4✔
366
    for i, block in enumerate(blocks):
4✔
367
        if i > 0:
4✔
368
            writer.write("\n\n")
4✔
369

370
        writer.write(block)
4✔
371

372
    writer.write("\n")
4✔
373

374
    return writer.getvalue(), None
4✔
375

376

377
# 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