aas-core-codegen 0.0.16__py3-none-any.whl → 0.0.17__py3-none-any.whl

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.
@@ -0,0 +1,1871 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # pylint: disable=missing-docstring
4
+
5
+ import ast
6
+ import inspect
7
+ import pathlib
8
+ import pickle
9
+ import re
10
+ import textwrap
11
+ import unittest
12
+ from typing import List, Dict, Optional, Final, Sequence
13
+
14
+ from icontract import require
15
+
16
+ from aas_core_codegen import intermediate
17
+ from aas_core_codegen.common import Identifier
18
+
19
+ # noinspection PyProtectedMember
20
+ from aas_core_codegen.intermediate import _types as intermediate_types
21
+
22
+ import tests.common
23
+
24
+
25
+ class TestPickle(unittest.TestCase):
26
+ def test_enumeration(self) -> None:
27
+ source = textwrap.dedent(
28
+ """\
29
+ from enum import Enum
30
+
31
+ class Some_enum(Enum):
32
+ Literal1 = "literal_1"
33
+ Literal2 = "literal_2"
34
+
35
+ __version__ = "dummy"
36
+ __xml_namespace__ = "https://dummy.com"
37
+ """
38
+ )
39
+
40
+ symbol_table, error = tests.common.translate_source_to_intermediate(
41
+ source=source
42
+ )
43
+ assert error is None and symbol_table is not None
44
+
45
+ some_enum = symbol_table.must_find_enumeration(Identifier("Some_enum"))
46
+
47
+ # NOTE (mristin):
48
+ # We first test that ID sets are working before pickling.
49
+ original_id_set = some_enum.literal_id_set
50
+ self.assertEqual(len(original_id_set), 2)
51
+ self.assertIn(id(some_enum.literals[0]), original_id_set)
52
+ self.assertIn(id(some_enum.literals[1]), original_id_set)
53
+
54
+ pickled_data = pickle.dumps(some_enum)
55
+ unpickled_enum = pickle.loads(pickled_data)
56
+
57
+ # NOTE (mristin):
58
+ # We now test that the unpickled ID sets are also working.
59
+ self.assertEqual(unpickled_enum.name, "Some_enum")
60
+ self.assertEqual(len(unpickled_enum.literals), 2)
61
+ self.assertEqual(unpickled_enum.literals[0].name, "Literal1")
62
+ self.assertEqual(unpickled_enum.literals[1].name, "Literal2")
63
+
64
+ new_id_set = unpickled_enum.literal_id_set
65
+ self.assertEqual(len(new_id_set), 2)
66
+ self.assertIn(id(unpickled_enum.literals[0]), new_id_set)
67
+ self.assertIn(id(unpickled_enum.literals[1]), new_id_set)
68
+
69
+ # NOTE (mristin):
70
+ # The ID sets should be different since objects have new IDs after unpickling.
71
+ self.assertNotEqual(original_id_set, new_id_set)
72
+
73
+ def test_abstract_class(self) -> None:
74
+ source = textwrap.dedent(
75
+ """\
76
+ @abstract
77
+ class Some_abstract_class:
78
+ some_property: int
79
+
80
+ @require(lambda some_property: some_property > 0)
81
+ def __init__(self, some_property: int) -> None:
82
+ self.some_property = some_property
83
+
84
+ __version__ = "dummy"
85
+ __xml_namespace__ = "https://dummy.com"
86
+ """
87
+ )
88
+
89
+ symbol_table, error = tests.common.translate_source_to_intermediate(
90
+ source=source
91
+ )
92
+ assert error is None and symbol_table is not None
93
+
94
+ some_abstract_class = symbol_table.must_find_abstract_class(
95
+ Identifier("Some_abstract_class")
96
+ )
97
+
98
+ pickled_data = pickle.dumps(some_abstract_class)
99
+ unpickled = pickle.loads(pickled_data)
100
+
101
+ assert isinstance(unpickled, intermediate.AbstractClass)
102
+
103
+ self.assertEqual(unpickled.name, "Some_abstract_class")
104
+ self.assertEqual(len(unpickled.properties), 1)
105
+ self.assertEqual(unpickled.properties[0].name, "some_property")
106
+
107
+ # Test that ID sets are rebuilt correctly
108
+ self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
109
+
110
+ def test_argument(self) -> None:
111
+ source = textwrap.dedent(
112
+ """\
113
+ class Some_class:
114
+ def some_method(self, some_arg: int) -> None:
115
+ pass
116
+
117
+ __version__ = "dummy"
118
+ __xml_namespace__ = "https://dummy.com"
119
+ """
120
+ )
121
+
122
+ symbol_table, error = tests.common.translate_source_to_intermediate(
123
+ source=source
124
+ )
125
+ assert error is None and symbol_table is not None
126
+
127
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
128
+ some_method = some_class.methods[0]
129
+ some_arg = some_method.arguments[0]
130
+
131
+ pickled_data = pickle.dumps(some_arg)
132
+ unpickled = pickle.loads(pickled_data)
133
+
134
+ assert isinstance(unpickled, intermediate.Argument)
135
+
136
+ self.assertEqual(unpickled.name, "some_arg")
137
+
138
+ def test_class(self) -> None:
139
+ source = textwrap.dedent(
140
+ """\
141
+ class Some_class:
142
+ some_property: int
143
+
144
+ def __init__(
145
+ self,
146
+ some_property: int
147
+ ) -> None:
148
+ self.some_property = some_property
149
+
150
+ __version__ = "dummy"
151
+ __xml_namespace__ = "https://dummy.com"
152
+ """
153
+ )
154
+
155
+ symbol_table, error = tests.common.translate_source_to_intermediate(
156
+ source=source
157
+ )
158
+ if error is not None:
159
+ raise AssertionError(tests.common.most_underlying_messages(error))
160
+ assert symbol_table is not None
161
+
162
+ some_class = symbol_table.must_find_class(Identifier("Some_class"))
163
+
164
+ pickled_data = pickle.dumps(some_class)
165
+ unpickled = pickle.loads(pickled_data)
166
+
167
+ assert isinstance(unpickled, intermediate.ConcreteClass)
168
+
169
+ self.assertEqual(unpickled.name, "Some_class")
170
+
171
+ self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
172
+
173
+ def test_concrete_class(self) -> None:
174
+ source = textwrap.dedent(
175
+ """\
176
+ class Some_concrete_class:
177
+ some_property: int
178
+
179
+ def __init__(
180
+ self,
181
+ some_property: int
182
+ ) -> None:
183
+ self.some_property = some_property
184
+
185
+ __version__ = "dummy"
186
+ __xml_namespace__ = "https://dummy.com"
187
+ """
188
+ )
189
+
190
+ symbol_table, error = tests.common.translate_source_to_intermediate(
191
+ source=source
192
+ )
193
+ if error is not None:
194
+ raise AssertionError(tests.common.most_underlying_messages(error))
195
+ assert symbol_table is not None
196
+
197
+ some_concrete_class = symbol_table.must_find_concrete_class(
198
+ Identifier("Some_concrete_class")
199
+ )
200
+
201
+ pickled_data = pickle.dumps(some_concrete_class)
202
+ unpickled = pickle.loads(pickled_data)
203
+
204
+ assert isinstance(unpickled, intermediate.ConcreteClass)
205
+
206
+ self.assertEqual(unpickled.name, "Some_concrete_class")
207
+ self.assertEqual(len(unpickled.properties), 1)
208
+
209
+ self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
210
+
211
+ def test_constant_primitive(self) -> None:
212
+ source = textwrap.dedent(
213
+ """\
214
+ Some_constant: str = constant_str(
215
+ value="some_value",
216
+ )
217
+
218
+ __version__ = "dummy"
219
+ __xml_namespace__ = "https://dummy.com"
220
+ """
221
+ )
222
+
223
+ symbol_table, error = tests.common.translate_source_to_intermediate(
224
+ source=source
225
+ )
226
+ if error is not None:
227
+ raise AssertionError(tests.common.most_underlying_messages(error))
228
+ assert symbol_table is not None
229
+
230
+ some_constant = symbol_table.must_find_constant_primitive(
231
+ Identifier("Some_constant")
232
+ )
233
+
234
+ pickled_data = pickle.dumps(some_constant)
235
+ unpickled = pickle.loads(pickled_data)
236
+
237
+ assert isinstance(unpickled, intermediate.ConstantPrimitive)
238
+
239
+ self.assertEqual(unpickled.name, "Some_constant")
240
+ self.assertEqual(unpickled.value, "some_value")
241
+
242
+ def test_constant_set_of_primitives(self) -> None:
243
+ source = textwrap.dedent(
244
+ """\
245
+ from aas_core_meta.marker import (
246
+ constant_set
247
+ )
248
+
249
+ Some_constant_set: Set[str] = constant_set(
250
+ values=["value1", "value2"]
251
+ )
252
+
253
+ __version__ = "dummy"
254
+ __xml_namespace__ = "https://dummy.com"
255
+ """
256
+ )
257
+
258
+ symbol_table, error = tests.common.translate_source_to_intermediate(
259
+ source=source
260
+ )
261
+ if error is not None:
262
+ raise AssertionError(tests.common.most_underlying_messages(error))
263
+ assert symbol_table is not None
264
+
265
+ some_constant_set = symbol_table.must_find_constant_set_of_primitives(
266
+ Identifier("Some_constant_set")
267
+ )
268
+
269
+ pickled_data = pickle.dumps(some_constant_set)
270
+ unpickled = pickle.loads(pickled_data)
271
+
272
+ assert isinstance(unpickled, intermediate.ConstantSetOfPrimitives)
273
+
274
+ self.assertEqual(unpickled.name, "Some_constant_set")
275
+ self.assertEqual(len(unpickled.literals), 2)
276
+
277
+ def test_constrained_primitive(self) -> None:
278
+ source = textwrap.dedent(
279
+ """\
280
+ @invariant(lambda self: len(self) > 0, "Non-empty")
281
+ class Some_constrained_primitive(str):
282
+ pass
283
+
284
+ __version__ = "dummy"
285
+ __xml_namespace__ = "https://dummy.com"
286
+ """
287
+ )
288
+
289
+ symbol_table, error = tests.common.translate_source_to_intermediate(
290
+ source=source
291
+ )
292
+ if error is not None:
293
+ raise AssertionError(tests.common.most_underlying_messages(error))
294
+ assert symbol_table is not None
295
+
296
+ some_constrained_primitive = symbol_table.must_find_constrained_primitive(
297
+ Identifier("Some_constrained_primitive")
298
+ )
299
+
300
+ pickled_data = pickle.dumps(some_constrained_primitive)
301
+ unpickled = pickle.loads(pickled_data)
302
+
303
+ assert isinstance(unpickled, intermediate.ConstrainedPrimitive)
304
+
305
+ self.assertEqual(unpickled.name, "Some_constrained_primitive")
306
+
307
+ self.assertIn(id(unpickled.invariants[0]), unpickled.invariant_id_set)
308
+
309
+ def test_constructor(self) -> None:
310
+ source = textwrap.dedent(
311
+ """\
312
+ class Some_class:
313
+ some_property: int
314
+
315
+ def __init__(self, some_property: int) -> None:
316
+ self.some_property = some_property
317
+
318
+ __version__ = "dummy"
319
+ __xml_namespace__ = "https://dummy.com"
320
+ """
321
+ )
322
+
323
+ symbol_table, error = tests.common.translate_source_to_intermediate(
324
+ source=source
325
+ )
326
+ if error is not None:
327
+ raise AssertionError(tests.common.most_underlying_messages(error))
328
+ assert symbol_table is not None
329
+
330
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
331
+ constructor = some_class.constructor
332
+
333
+ pickled_data = pickle.dumps(constructor)
334
+ unpickled = pickle.loads(pickled_data)
335
+
336
+ assert isinstance(unpickled, intermediate.Constructor)
337
+
338
+ self.assertEqual(len(unpickled.arguments), 1)
339
+
340
+ def test_contract(self) -> None:
341
+ source = textwrap.dedent(
342
+ """\
343
+ class Some_class:
344
+ @require(lambda self: True)
345
+ @ensure(lambda result: True)
346
+ def some_method(self) -> bool:
347
+ return True
348
+
349
+ __version__ = "dummy"
350
+ __xml_namespace__ = "https://dummy.com"
351
+ """
352
+ )
353
+
354
+ symbol_table, error = tests.common.translate_source_to_intermediate(
355
+ source=source
356
+ )
357
+ if error is not None:
358
+ raise AssertionError(tests.common.most_underlying_messages(error))
359
+ assert symbol_table is not None
360
+
361
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
362
+ some_method = some_class.methods[0]
363
+ contract = some_method.contracts.preconditions[0]
364
+
365
+ pickled_data = pickle.dumps(contract)
366
+ unpickled = pickle.loads(pickled_data)
367
+
368
+ assert isinstance(unpickled, intermediate.Contract)
369
+
370
+ self.assertIsNotNone(unpickled.body)
371
+
372
+ def test_contracts(self) -> None:
373
+ source = textwrap.dedent(
374
+ """\
375
+ class Some_class:
376
+ @require(lambda self: True)
377
+ def some_method(self) -> None:
378
+ pass
379
+
380
+ __version__ = "dummy"
381
+ __xml_namespace__ = "https://dummy.com"
382
+ """
383
+ )
384
+
385
+ symbol_table, error = tests.common.translate_source_to_intermediate(
386
+ source=source
387
+ )
388
+ if error is not None:
389
+ raise AssertionError(tests.common.most_underlying_messages(error))
390
+ assert symbol_table is not None
391
+
392
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
393
+ some_method = some_class.methods[0]
394
+ contracts = some_method.contracts
395
+
396
+ pickled_data = pickle.dumps(contracts)
397
+ unpickled = pickle.loads(pickled_data)
398
+
399
+ assert isinstance(unpickled, intermediate.Contracts)
400
+
401
+ self.assertEqual(len(unpickled.preconditions), 1)
402
+
403
+ def test_default_primitive(self) -> None:
404
+ source = textwrap.dedent(
405
+ """\
406
+ class Some_class:
407
+ some_property: str
408
+
409
+ def __init__(self, some_property: str = 'some_default') -> None:
410
+ self.some_property = some_property
411
+
412
+ __version__ = "dummy"
413
+ __xml_namespace__ = "https://dummy.com"
414
+ """
415
+ )
416
+
417
+ symbol_table, error = tests.common.translate_source_to_intermediate(
418
+ source=source
419
+ )
420
+ if error is not None:
421
+ raise AssertionError(tests.common.most_underlying_messages(error))
422
+ assert symbol_table is not None
423
+
424
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
425
+
426
+ arg = some_class.constructor.arguments_by_name[Identifier("some_property")]
427
+
428
+ default = arg.default
429
+
430
+ pickled_data = pickle.dumps(default)
431
+ unpickled = pickle.loads(pickled_data)
432
+
433
+ assert isinstance(unpickled, intermediate.DefaultPrimitive)
434
+
435
+ def test_default_enumeration_literal(self) -> None:
436
+ source = textwrap.dedent(
437
+ """\
438
+ class Some_enum(Enum):
439
+ Literal1 = "literal-1"
440
+ Literal2 = "literal-2"
441
+
442
+ class Some_class:
443
+ some_property: Some_enum
444
+
445
+ def __init__(
446
+ self,
447
+ some_property: Some_enum = Some_enum.Literal1
448
+ ) -> None:
449
+ self.some_property = some_property
450
+
451
+ __version__ = "dummy"
452
+ __xml_namespace__ = "https://dummy.com"
453
+ """
454
+ )
455
+
456
+ symbol_table, error = tests.common.translate_source_to_intermediate(
457
+ source=source
458
+ )
459
+ if error is not None:
460
+ raise AssertionError(tests.common.most_underlying_messages(error))
461
+ assert symbol_table is not None
462
+
463
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
464
+
465
+ arg = some_class.constructor.arguments_by_name[Identifier("some_property")]
466
+
467
+ default = arg.default
468
+
469
+ pickled_data = pickle.dumps(default)
470
+ unpickled = pickle.loads(pickled_data)
471
+
472
+ assert isinstance(unpickled, intermediate.DefaultEnumerationLiteral)
473
+
474
+ def test_description_of_constant(self) -> None:
475
+ source = textwrap.dedent(
476
+ """\
477
+ Some_constant: str = constant_str(
478
+ value="some_value",
479
+ description="This is some constant."
480
+ )
481
+
482
+ __version__ = "dummy"
483
+ __xml_namespace__ = "https://dummy.com"
484
+ """
485
+ )
486
+
487
+ symbol_table, error = tests.common.translate_source_to_intermediate(
488
+ source=source
489
+ )
490
+ if error is not None:
491
+ raise AssertionError(tests.common.most_underlying_messages(error))
492
+ assert symbol_table is not None
493
+
494
+ some_constant = symbol_table.must_find_constant_primitive(
495
+ Identifier("Some_constant")
496
+ )
497
+ description = some_constant.description
498
+ assert description is not None
499
+
500
+ pickled_data = pickle.dumps(description)
501
+ unpickled = pickle.loads(pickled_data)
502
+
503
+ assert isinstance(unpickled, intermediate.DescriptionOfConstant), str(
504
+ type(unpickled)
505
+ )
506
+
507
+ self.assertEqual(unpickled.summary[0], "This is some constant.")
508
+
509
+ def test_description_of_enumeration_literal(self) -> None:
510
+ source = textwrap.dedent(
511
+ """\
512
+ from enum import Enum
513
+
514
+ class Some_enum(Enum):
515
+ literal1 = "value1"
516
+ \"\"\"Describe the literal.\"\"\"
517
+
518
+ __version__ = "dummy"
519
+ __xml_namespace__ = "https://dummy.com"
520
+ """
521
+ )
522
+
523
+ symbol_table, error = tests.common.translate_source_to_intermediate(
524
+ source=source
525
+ )
526
+ if error is not None:
527
+ raise AssertionError(tests.common.most_underlying_messages(error))
528
+ assert symbol_table is not None
529
+
530
+ some_enum = symbol_table.must_find_enumeration(Identifier("Some_enum"))
531
+ literal = some_enum.literals[0]
532
+ description = literal.description
533
+
534
+ pickled_data = pickle.dumps(description)
535
+ unpickled = pickle.loads(pickled_data)
536
+
537
+ assert isinstance(unpickled, intermediate.DescriptionOfEnumerationLiteral)
538
+
539
+ self.assertEqual(unpickled.summary[0], "Describe the literal.")
540
+
541
+ def test_description_of_meta_model(self) -> None:
542
+ source = textwrap.dedent(
543
+ """\
544
+ \"\"\"Meta-model description.\"\"\"
545
+
546
+ class Some_class:
547
+ pass
548
+
549
+ __version__ = "dummy"
550
+ __xml_namespace__ = "https://dummy.com"
551
+ """
552
+ )
553
+
554
+ symbol_table, error = tests.common.translate_source_to_intermediate(
555
+ source=source
556
+ )
557
+ if error is not None:
558
+ raise AssertionError(tests.common.most_underlying_messages(error))
559
+ assert symbol_table is not None
560
+
561
+ meta_model = symbol_table.meta_model
562
+ description = meta_model.description
563
+
564
+ pickled_data = pickle.dumps(description)
565
+ unpickled = pickle.loads(pickled_data)
566
+
567
+ assert isinstance(unpickled, intermediate.DescriptionOfMetaModel)
568
+
569
+ self.assertEqual(unpickled.summary[0], "Meta-model description.")
570
+
571
+ def test_description_of_our_type(self) -> None:
572
+ source = textwrap.dedent(
573
+ """\
574
+ class Some_class:
575
+ \"\"\"Describe the class.\"\"\"
576
+ pass
577
+
578
+ __version__ = "dummy"
579
+ __xml_namespace__ = "https://dummy.com"
580
+ """
581
+ )
582
+
583
+ symbol_table, error = tests.common.translate_source_to_intermediate(
584
+ source=source
585
+ )
586
+ if error is not None:
587
+ raise AssertionError(tests.common.most_underlying_messages(error))
588
+ assert symbol_table is not None
589
+
590
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
591
+ description = some_class.description
592
+
593
+ pickled_data = pickle.dumps(description)
594
+ unpickled = pickle.loads(pickled_data)
595
+
596
+ assert isinstance(unpickled, intermediate.DescriptionOfOurType)
597
+
598
+ self.assertEqual(unpickled.summary[0], "Describe the class.")
599
+
600
+ def test_description_of_property(self) -> None:
601
+ source = textwrap.dedent(
602
+ """\
603
+ class Some_class:
604
+ some_property: int
605
+ \"\"\"Describe the property.\"\"\"
606
+
607
+ def __init__(
608
+ self,
609
+ some_property: int
610
+ ) -> None:
611
+ self.some_property = some_property
612
+
613
+ __version__ = "dummy"
614
+ __xml_namespace__ = "https://dummy.com"
615
+ """
616
+ )
617
+
618
+ symbol_table, error = tests.common.translate_source_to_intermediate(
619
+ source=source
620
+ )
621
+ if error is not None:
622
+ raise AssertionError(tests.common.most_underlying_messages(error))
623
+ assert symbol_table is not None
624
+
625
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
626
+ some_property = some_class.properties[0]
627
+ description = some_property.description
628
+
629
+ pickled_data = pickle.dumps(description)
630
+ unpickled = pickle.loads(pickled_data)
631
+
632
+ assert isinstance(unpickled, intermediate.DescriptionOfProperty)
633
+
634
+ self.assertEqual(unpickled.summary[0], "Describe the property.")
635
+
636
+ def test_description_of_signature(self) -> None:
637
+ source = textwrap.dedent(
638
+ """\
639
+ class Some_class:
640
+ def some_method(self) -> None:
641
+ \"\"\"Describe the method.\"\"\"
642
+ pass
643
+
644
+ __version__ = "dummy"
645
+ __xml_namespace__ = "https://dummy.com"
646
+ """
647
+ )
648
+
649
+ symbol_table, error = tests.common.translate_source_to_intermediate(
650
+ source=source
651
+ )
652
+ if error is not None:
653
+ raise AssertionError(tests.common.most_underlying_messages(error))
654
+ assert symbol_table is not None
655
+
656
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
657
+ some_method = some_class.methods[0]
658
+ description = some_method.description
659
+
660
+ pickled_data = pickle.dumps(description)
661
+ unpickled = pickle.loads(pickled_data)
662
+
663
+ assert isinstance(unpickled, intermediate.DescriptionOfSignature)
664
+
665
+ self.assertEqual(unpickled.summary[0], "Describe the method.")
666
+
667
+ def test_enumeration_literal(self) -> None:
668
+ source = textwrap.dedent(
669
+ """\
670
+ from enum import Enum
671
+
672
+ class Some_enum(Enum):
673
+ literal1 = "value1"
674
+
675
+ __version__ = "dummy"
676
+ __xml_namespace__ = "https://dummy.com"
677
+ """
678
+ )
679
+
680
+ symbol_table, error = tests.common.translate_source_to_intermediate(
681
+ source=source
682
+ )
683
+ if error is not None:
684
+ raise AssertionError(tests.common.most_underlying_messages(error))
685
+ assert symbol_table is not None
686
+
687
+ some_enum = symbol_table.must_find_enumeration(Identifier("Some_enum"))
688
+ literal = some_enum.literals[0]
689
+
690
+ pickled_data = pickle.dumps(literal)
691
+ unpickled = pickle.loads(pickled_data)
692
+
693
+ assert isinstance(unpickled, intermediate.EnumerationLiteral)
694
+
695
+ self.assertEqual(unpickled.name, "literal1")
696
+ self.assertEqual(unpickled.value, "value1")
697
+
698
+ def test_implementation_specific_method(self) -> None:
699
+ source = textwrap.dedent(
700
+ """\
701
+ class Some_class:
702
+ @implementation_specific
703
+ def some_method(self) -> None:
704
+ pass
705
+
706
+ __version__ = "dummy"
707
+ __xml_namespace__ = "https://dummy.com"
708
+ """
709
+ )
710
+
711
+ symbol_table, error = tests.common.translate_source_to_intermediate(
712
+ source=source
713
+ )
714
+ if error is not None:
715
+ raise AssertionError(tests.common.most_underlying_messages(error))
716
+ assert symbol_table is not None
717
+
718
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
719
+ some_method = some_class.methods[0]
720
+
721
+ pickled_data = pickle.dumps(some_method)
722
+ unpickled = pickle.loads(pickled_data)
723
+
724
+ assert isinstance(unpickled, intermediate.ImplementationSpecificMethod)
725
+
726
+ self.assertEqual(unpickled.name, "some_method")
727
+
728
+ def test_implementation_specific_verification(self) -> None:
729
+ source = textwrap.dedent(
730
+ """\
731
+ @verification
732
+ @implementation_specific
733
+ def some_verification(x: int) -> bool:
734
+ pass
735
+
736
+ __version__ = "dummy"
737
+ __xml_namespace__ = "https://dummy.com"
738
+ """
739
+ )
740
+
741
+ symbol_table, error = tests.common.translate_source_to_intermediate(
742
+ source=source
743
+ )
744
+ if error is not None:
745
+ raise AssertionError(tests.common.most_underlying_messages(error))
746
+ assert symbol_table is not None
747
+
748
+ verification = symbol_table.verification_functions[0]
749
+
750
+ pickled_data = pickle.dumps(verification)
751
+ unpickled = pickle.loads(pickled_data)
752
+
753
+ assert isinstance(unpickled, intermediate.ImplementationSpecificVerification)
754
+
755
+ self.assertEqual(unpickled.name, "some_verification")
756
+
757
+ def test_interface(self) -> None:
758
+ source = textwrap.dedent(
759
+ """\
760
+ @abstract
761
+ class Some_abstract_class:
762
+ some_property: int
763
+
764
+ def __init__(
765
+ self,
766
+ some_property: int
767
+ ) -> None:
768
+ self.some_property = some_property
769
+
770
+ def some_func(self) -> None:
771
+ pass
772
+
773
+ __version__ = "dummy"
774
+ __xml_namespace__ = "https://dummy.com"
775
+ """
776
+ )
777
+
778
+ symbol_table, error = tests.common.translate_source_to_intermediate(
779
+ source=source
780
+ )
781
+ if error is not None:
782
+ raise AssertionError(tests.common.most_underlying_messages(error))
783
+ assert symbol_table is not None
784
+
785
+ some_abstract_class = symbol_table.must_find_abstract_class(
786
+ Identifier("Some_abstract_class")
787
+ )
788
+
789
+ interface = some_abstract_class.interface
790
+
791
+ pickled_data = pickle.dumps(interface)
792
+ unpickled = pickle.loads(pickled_data)
793
+
794
+ assert isinstance(unpickled, intermediate.Interface)
795
+
796
+ self.assertEqual(unpickled.name, "Some_abstract_class")
797
+
798
+ self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
799
+
800
+ def test_invariant(self) -> None:
801
+ source = textwrap.dedent(
802
+ """\
803
+ @invariant(lambda self: self.some_property > 0, "Some property is positive")
804
+ class Some_class:
805
+ some_property: int
806
+
807
+ def __init__(self, some_property: int) -> None:
808
+ self.some_property = some_property
809
+
810
+ __version__ = "dummy"
811
+ __xml_namespace__ = "https://dummy.com"
812
+ """
813
+ )
814
+
815
+ symbol_table, error = tests.common.translate_source_to_intermediate(
816
+ source=source
817
+ )
818
+ if error is not None:
819
+ raise AssertionError(tests.common.most_underlying_messages(error))
820
+ assert symbol_table is not None
821
+
822
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
823
+ invariant = some_class.invariants[0]
824
+
825
+ pickled_data = pickle.dumps(invariant)
826
+ unpickled = pickle.loads(pickled_data)
827
+
828
+ assert isinstance(unpickled, intermediate.Invariant)
829
+
830
+ self.assertIsNotNone(unpickled.body)
831
+
832
+ def test_list_type_annotation(self) -> None:
833
+ source = textwrap.dedent(
834
+ """\
835
+ class Some_class:
836
+ some_property: List[str]
837
+
838
+ def __init__(
839
+ self,
840
+ some_property: List[str]
841
+ ) -> None:
842
+ self.some_property = some_property
843
+
844
+ __version__ = "dummy"
845
+ __xml_namespace__ = "https://dummy.com"
846
+ """
847
+ )
848
+
849
+ symbol_table, error = tests.common.translate_source_to_intermediate(
850
+ source=source
851
+ )
852
+ if error is not None:
853
+ raise AssertionError(tests.common.most_underlying_messages(error))
854
+ assert symbol_table is not None
855
+
856
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
857
+ some_property = some_class.properties[0]
858
+ type_annotation = some_property.type_annotation
859
+
860
+ pickled_data = pickle.dumps(type_annotation)
861
+ unpickled = pickle.loads(pickled_data)
862
+
863
+ self.assertIsInstance(unpickled, intermediate_types.ListTypeAnnotation)
864
+
865
+ def test_meta_model(self) -> None:
866
+ source = textwrap.dedent(
867
+ """\
868
+ class Some_class:
869
+ pass
870
+
871
+ __version__ = "dummy"
872
+ __xml_namespace__ = "https://dummy.com"
873
+ """
874
+ )
875
+
876
+ symbol_table, error = tests.common.translate_source_to_intermediate(
877
+ source=source
878
+ )
879
+ if error is not None:
880
+ raise AssertionError(tests.common.most_underlying_messages(error))
881
+ assert symbol_table is not None
882
+
883
+ meta_model = symbol_table.meta_model
884
+
885
+ pickled_data = pickle.dumps(meta_model)
886
+ unpickled = pickle.loads(pickled_data)
887
+
888
+ assert isinstance(unpickled, intermediate_types.MetaModel)
889
+
890
+ self.assertEqual(unpickled.version, "dummy")
891
+
892
+ def test_method(self) -> None:
893
+ source = textwrap.dedent(
894
+ """\
895
+ class Some_class:
896
+ def some_method(self) -> None:
897
+ pass
898
+
899
+ __version__ = "dummy"
900
+ __xml_namespace__ = "https://dummy.com"
901
+ """
902
+ )
903
+
904
+ symbol_table, error = tests.common.translate_source_to_intermediate(
905
+ source=source
906
+ )
907
+ if error is not None:
908
+ raise AssertionError(tests.common.most_underlying_messages(error))
909
+ assert symbol_table is not None
910
+
911
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
912
+ some_method = some_class.methods[0]
913
+
914
+ pickled_data = pickle.dumps(some_method)
915
+ unpickled = pickle.loads(pickled_data)
916
+
917
+ assert isinstance(unpickled, intermediate.UnderstoodMethod)
918
+
919
+ self.assertEqual(unpickled.name, "some_method")
920
+
921
+ def test_optional_type_annotation(self) -> None:
922
+ source = textwrap.dedent(
923
+ """\
924
+ class Some_class:
925
+ some_property: Optional[str]
926
+
927
+ def __init__(
928
+ self,
929
+ some_property: Optional[str] = None
930
+ ) -> None:
931
+ self.some_property = some_property
932
+
933
+ __version__ = "dummy"
934
+ __xml_namespace__ = "https://dummy.com"
935
+ """
936
+ )
937
+
938
+ symbol_table, error = tests.common.translate_source_to_intermediate(
939
+ source=source
940
+ )
941
+ if error is not None:
942
+ raise AssertionError(tests.common.most_underlying_messages(error))
943
+ assert symbol_table is not None
944
+
945
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
946
+ some_property = some_class.properties[0]
947
+ type_annotation = some_property.type_annotation
948
+
949
+ pickled_data = pickle.dumps(type_annotation)
950
+ unpickled = pickle.loads(pickled_data)
951
+
952
+ self.assertIsInstance(unpickled, intermediate_types.OptionalTypeAnnotation)
953
+
954
+ def test_our_type_annotation(self) -> None:
955
+ source = textwrap.dedent(
956
+ """\
957
+ class Some_class:
958
+ pass
959
+
960
+ class Some_another_class:
961
+ some_property: Some_class
962
+
963
+ def __init__(
964
+ self,
965
+ some_property: Some_class
966
+ ) -> None:
967
+ self.some_property = some_property
968
+
969
+ __version__ = "dummy"
970
+ __xml_namespace__ = "https://dummy.com"
971
+ """
972
+ )
973
+
974
+ symbol_table, error = tests.common.translate_source_to_intermediate(
975
+ source=source
976
+ )
977
+ if error is not None:
978
+ raise AssertionError(tests.common.most_underlying_messages(error))
979
+ assert symbol_table is not None
980
+
981
+ some_another_class = symbol_table.must_find_concrete_class(
982
+ Identifier("Some_another_class")
983
+ )
984
+ some_property = some_another_class.properties[0]
985
+ type_annotation = some_property.type_annotation
986
+
987
+ pickled_data = pickle.dumps(type_annotation)
988
+ unpickled = pickle.loads(pickled_data)
989
+
990
+ self.assertIsInstance(unpickled, intermediate_types.OurTypeAnnotation)
991
+
992
+ def test_pattern_verification(self) -> None:
993
+ source = textwrap.dedent(
994
+ """\
995
+ @verification
996
+ def some_verification(x: str) -> bool:
997
+ return match(r"^[a-z]+$", x) is not None
998
+
999
+ __version__ = "dummy"
1000
+ __xml_namespace__ = "https://dummy.com"
1001
+ """
1002
+ )
1003
+
1004
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1005
+ source=source
1006
+ )
1007
+ if error is not None:
1008
+ raise AssertionError(tests.common.most_underlying_messages(error))
1009
+ assert symbol_table is not None
1010
+
1011
+ verification = symbol_table.verification_functions[0]
1012
+
1013
+ pickled_data = pickle.dumps(verification)
1014
+ unpickled = pickle.loads(pickled_data)
1015
+
1016
+ assert isinstance(unpickled, intermediate.PatternVerification)
1017
+
1018
+ self.assertEqual(unpickled.name, "some_verification")
1019
+
1020
+ def test_primitive_set_literal(self) -> None:
1021
+ source = textwrap.dedent(
1022
+ """\
1023
+ from aas_core_meta.marker import (
1024
+ constant_set
1025
+ )
1026
+
1027
+ Some_constant_set: Set[str] = constant_set(
1028
+ values=["value1", "value2"]
1029
+ )
1030
+
1031
+ __version__ = "dummy"
1032
+ __xml_namespace__ = "https://dummy.com"
1033
+ """
1034
+ )
1035
+
1036
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1037
+ source=source
1038
+ )
1039
+ if error is not None:
1040
+ raise AssertionError(tests.common.most_underlying_messages(error))
1041
+ assert symbol_table is not None
1042
+
1043
+ some_constant_set = symbol_table.must_find_constant_set_of_primitives(
1044
+ Identifier("Some_constant_set")
1045
+ )
1046
+ literal = some_constant_set.literals[0]
1047
+
1048
+ pickled_data = pickle.dumps(literal)
1049
+ unpickled = pickle.loads(pickled_data)
1050
+
1051
+ assert isinstance(unpickled, intermediate.PrimitiveSetLiteral)
1052
+
1053
+ self.assertEqual(unpickled.value, "value1")
1054
+
1055
+ def test_primitive_type(self) -> None:
1056
+ source = textwrap.dedent(
1057
+ """\
1058
+ class Some_class:
1059
+ some_property: str
1060
+
1061
+ def __init__(
1062
+ self,
1063
+ some_property: str
1064
+ ) -> None:
1065
+ self.some_property = some_property
1066
+
1067
+ __version__ = "dummy"
1068
+ __xml_namespace__ = "https://dummy.com"
1069
+ """
1070
+ )
1071
+
1072
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1073
+ source=source
1074
+ )
1075
+ if error is not None:
1076
+ raise AssertionError(tests.common.most_underlying_messages(error))
1077
+ assert symbol_table is not None
1078
+
1079
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1080
+ some_property = some_class.properties[0]
1081
+ type_annotation = some_property.type_annotation
1082
+ assert isinstance(type_annotation, intermediate_types.PrimitiveTypeAnnotation)
1083
+ primitive_type = type_annotation.a_type
1084
+
1085
+ pickled_data = pickle.dumps(primitive_type)
1086
+ unpickled = pickle.loads(pickled_data)
1087
+
1088
+ self.assertEqual(unpickled, intermediate_types.PrimitiveType.STR)
1089
+
1090
+ def test_primitive_type_annotation(self) -> None:
1091
+ source = textwrap.dedent(
1092
+ """\
1093
+ class Some_class:
1094
+ some_property: str
1095
+
1096
+ def __init__(
1097
+ self,
1098
+ some_property: str
1099
+ ) -> None:
1100
+ self.some_property = some_property
1101
+
1102
+ __version__ = "dummy"
1103
+ __xml_namespace__ = "https://dummy.com"
1104
+ """
1105
+ )
1106
+
1107
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1108
+ source=source
1109
+ )
1110
+ if error is not None:
1111
+ raise AssertionError(tests.common.most_underlying_messages(error))
1112
+ assert symbol_table is not None
1113
+
1114
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1115
+ some_property = some_class.properties[0]
1116
+ type_annotation = some_property.type_annotation
1117
+
1118
+ pickled_data = pickle.dumps(type_annotation)
1119
+ unpickled = pickle.loads(pickled_data)
1120
+
1121
+ self.assertIsInstance(unpickled, intermediate_types.PrimitiveTypeAnnotation)
1122
+
1123
+ def test_property(self) -> None:
1124
+ source = textwrap.dedent(
1125
+ """\
1126
+ class Some_class:
1127
+ some_property: str
1128
+
1129
+ def __init__(
1130
+ self,
1131
+ some_property: str
1132
+ ) -> None:
1133
+ self.some_property = some_property
1134
+
1135
+ __version__ = "dummy"
1136
+ __xml_namespace__ = "https://dummy.com"
1137
+ """
1138
+ )
1139
+
1140
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1141
+ source=source
1142
+ )
1143
+ if error is not None:
1144
+ raise AssertionError(tests.common.most_underlying_messages(error))
1145
+ assert symbol_table is not None
1146
+
1147
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1148
+ some_property = some_class.properties[0]
1149
+
1150
+ pickled_data = pickle.dumps(some_property)
1151
+ unpickled = pickle.loads(pickled_data)
1152
+
1153
+ assert isinstance(unpickled, intermediate.Property)
1154
+
1155
+ self.assertEqual(unpickled.name, "some_property")
1156
+
1157
+ def test_serialization(self) -> None:
1158
+ source = textwrap.dedent(
1159
+ """\
1160
+ @serialization(with_model_type=True)
1161
+ class Some_class:
1162
+ some_property: str
1163
+
1164
+ def __init__(self, some_property: str) -> None:
1165
+ self.some_property = some_property
1166
+
1167
+ __version__ = "dummy"
1168
+ __xml_namespace__ = "https://dummy.com"
1169
+ """
1170
+ )
1171
+
1172
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1173
+ source=source
1174
+ )
1175
+ if error is not None:
1176
+ raise AssertionError(tests.common.most_underlying_messages(error))
1177
+ assert symbol_table is not None
1178
+
1179
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1180
+ serialization = some_class.serialization
1181
+
1182
+ pickled_data = pickle.dumps(serialization)
1183
+ unpickled = pickle.loads(pickled_data)
1184
+
1185
+ assert isinstance(unpickled, intermediate.Serialization)
1186
+
1187
+ self.assertEqual(unpickled.with_model_type, True)
1188
+
1189
+ def test_signature(self) -> None:
1190
+ source = textwrap.dedent(
1191
+ """\
1192
+ @abstract
1193
+ class Some_abstract_class:
1194
+ some_property: int
1195
+
1196
+ def __init__(self, some_property: int) -> None:
1197
+ self.some_property = some_property
1198
+
1199
+ def some_func(self) -> None:
1200
+ pass
1201
+
1202
+
1203
+ __version__ = "dummy"
1204
+ __xml_namespace__ = "https://dummy.com"
1205
+ """
1206
+ )
1207
+
1208
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1209
+ source=source
1210
+ )
1211
+ if error is not None:
1212
+ raise AssertionError(tests.common.most_underlying_messages(error))
1213
+ assert symbol_table is not None
1214
+
1215
+ some_abstract_class = symbol_table.must_find_abstract_class(
1216
+ Identifier("Some_abstract_class")
1217
+ )
1218
+
1219
+ signature = some_abstract_class.interface.signatures[0]
1220
+
1221
+ pickled_data = pickle.dumps(signature)
1222
+ unpickled = pickle.loads(pickled_data)
1223
+
1224
+ assert isinstance(unpickled, intermediate.Signature)
1225
+
1226
+ self.assertEqual(unpickled.name, "some_func")
1227
+
1228
+ def test_signature_like(self) -> None:
1229
+ source = textwrap.dedent(
1230
+ """\
1231
+ @abstract
1232
+ class Some_abstract_class:
1233
+ some_property: int
1234
+
1235
+ def __init__(self, some_property: int) -> None:
1236
+ self.some_property = some_property
1237
+
1238
+ def some_func(self) -> None:
1239
+ pass
1240
+
1241
+
1242
+ __version__ = "dummy"
1243
+ __xml_namespace__ = "https://dummy.com"
1244
+ """
1245
+ )
1246
+
1247
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1248
+ source=source
1249
+ )
1250
+ if error is not None:
1251
+ raise AssertionError(tests.common.most_underlying_messages(error))
1252
+ assert symbol_table is not None
1253
+
1254
+ source = textwrap.dedent(
1255
+ """\
1256
+ @abstract
1257
+ class Some_abstract_class:
1258
+ some_property: int
1259
+
1260
+ @require(lambda some_property: some_property > 0)
1261
+ def __init__(self, some_property: int) -> None:
1262
+ self.some_property = some_property
1263
+
1264
+ def some_func(self) -> None:
1265
+ pass
1266
+
1267
+
1268
+ __version__ = "dummy"
1269
+ __xml_namespace__ = "https://dummy.com"
1270
+ """
1271
+ )
1272
+
1273
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1274
+ source=source
1275
+ )
1276
+ if error is not None:
1277
+ raise AssertionError(tests.common.most_underlying_messages(error))
1278
+ assert symbol_table is not None
1279
+
1280
+ some_abstract_class = symbol_table.must_find_abstract_class(
1281
+ Identifier("Some_abstract_class")
1282
+ )
1283
+
1284
+ signature_like: intermediate_types.SignatureLike = some_abstract_class.methods[
1285
+ 0
1286
+ ]
1287
+
1288
+ pickled_data = pickle.dumps(signature_like)
1289
+ unpickled = pickle.loads(pickled_data)
1290
+
1291
+ assert isinstance(unpickled, intermediate_types.SignatureLike)
1292
+
1293
+ self.assertEqual(unpickled.name, "some_func")
1294
+
1295
+ def test_snapshot(self) -> None:
1296
+ source = textwrap.dedent(
1297
+ """\
1298
+ class Some_class:
1299
+ some_property: int
1300
+
1301
+ def __init__(self, some_property: int) -> None:
1302
+ self.some_property = some_property
1303
+
1304
+ @snapshot(lambda self: self.some_property + 1)
1305
+ def some_method(self) -> None:
1306
+ pass
1307
+
1308
+ __version__ = "dummy"
1309
+ __xml_namespace__ = "https://dummy.com"
1310
+ """
1311
+ )
1312
+
1313
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1314
+ source=source
1315
+ )
1316
+ if error is not None:
1317
+ raise AssertionError(tests.common.most_underlying_messages(error))
1318
+ assert symbol_table is not None
1319
+
1320
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1321
+ some_method = some_class.methods[0]
1322
+ snapshot = some_method.contracts.snapshots[0]
1323
+
1324
+ pickled_data = pickle.dumps(snapshot)
1325
+ unpickled = pickle.loads(pickled_data)
1326
+
1327
+ assert isinstance(unpickled, intermediate.Snapshot)
1328
+
1329
+ self.assertIsNotNone(unpickled.body)
1330
+
1331
+ def test_summary_remarks_constraints_description(self) -> None:
1332
+ source = textwrap.dedent(
1333
+ """\
1334
+ class Some_class:
1335
+ \"\"\"
1336
+ Summary line.
1337
+
1338
+ Some remark.
1339
+
1340
+ :constraint A10: Soem constraint
1341
+ \"\"\"
1342
+
1343
+ __version__ = "dummy"
1344
+ __xml_namespace__ = "https://dummy.com"
1345
+ """
1346
+ )
1347
+
1348
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1349
+ source=source
1350
+ )
1351
+ if error is not None:
1352
+ raise AssertionError(tests.common.most_underlying_messages(error))
1353
+ assert symbol_table is not None
1354
+
1355
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1356
+ description = some_class.description
1357
+
1358
+ pickled_data = pickle.dumps(description)
1359
+ unpickled = pickle.loads(pickled_data)
1360
+
1361
+ assert isinstance(unpickled, intermediate.SummaryRemarksConstraintsDescription)
1362
+
1363
+ self.assertEqual(unpickled.summary[0], "Summary line.")
1364
+
1365
+ def test_summary_remarks_description(self) -> None:
1366
+ source = textwrap.dedent(
1367
+ """\
1368
+ from enum import Enum
1369
+
1370
+ class Some_class:
1371
+ \"\"\"
1372
+ Summary line.
1373
+
1374
+ Some remarks.
1375
+
1376
+ Some description.
1377
+ \"\"\"
1378
+
1379
+ __version__ = "dummy"
1380
+ __xml_namespace__ = "https://dummy.com"
1381
+ """
1382
+ )
1383
+
1384
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1385
+ source=source
1386
+ )
1387
+ if error is not None:
1388
+ raise AssertionError(tests.common.most_underlying_messages(error))
1389
+ assert symbol_table is not None
1390
+
1391
+ some_class = symbol_table.must_find_class(Identifier("Some_class"))
1392
+ description = some_class.description
1393
+
1394
+ pickled_data = pickle.dumps(description)
1395
+ unpickled = pickle.loads(pickled_data)
1396
+
1397
+ assert isinstance(unpickled, intermediate.SummaryRemarksDescription), str(
1398
+ type(unpickled)
1399
+ )
1400
+
1401
+ self.assertEqual(unpickled.summary[0], "Summary line.")
1402
+
1403
+ def test_symbol_table(self) -> None:
1404
+ source = textwrap.dedent(
1405
+ """\
1406
+ class Some_class:
1407
+ pass
1408
+
1409
+ __version__ = "dummy"
1410
+ __xml_namespace__ = "https://dummy.com"
1411
+ """
1412
+ )
1413
+
1414
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1415
+ source=source
1416
+ )
1417
+ if error is not None:
1418
+ raise AssertionError(tests.common.most_underlying_messages(error))
1419
+ assert symbol_table is not None
1420
+
1421
+ pickled_data = pickle.dumps(symbol_table)
1422
+ unpickled = pickle.loads(pickled_data)
1423
+
1424
+ assert isinstance(unpickled, intermediate.SymbolTable)
1425
+
1426
+ self.assertEqual(len(unpickled.concrete_classes), 1)
1427
+
1428
+ def test_transpilable_verification(self) -> None:
1429
+ source = textwrap.dedent(
1430
+ """\
1431
+ @verification
1432
+ def some_verification(x: int) -> bool:
1433
+ return x > 0
1434
+
1435
+ __version__ = "dummy"
1436
+ __xml_namespace__ = "https://dummy.com"
1437
+ """
1438
+ )
1439
+
1440
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1441
+ source=source
1442
+ )
1443
+ if error is not None:
1444
+ raise AssertionError(tests.common.most_underlying_messages(error))
1445
+ assert symbol_table is not None
1446
+
1447
+ verification = symbol_table.verification_functions[0]
1448
+
1449
+ pickled_data = pickle.dumps(verification)
1450
+ unpickled = pickle.loads(pickled_data)
1451
+
1452
+ assert isinstance(unpickled, intermediate.TranspilableVerification)
1453
+
1454
+ self.assertEqual(unpickled.name, "some_verification")
1455
+
1456
+ def test_type_annotation(self) -> None:
1457
+ source = textwrap.dedent(
1458
+ """\
1459
+ class Some_class:
1460
+ some_property: str
1461
+
1462
+ def __init__(
1463
+ self,
1464
+ some_property: str
1465
+ ) -> None:
1466
+ self.some_property = some_property
1467
+
1468
+ __version__ = "dummy"
1469
+ __xml_namespace__ = "https://dummy.com"
1470
+ """
1471
+ )
1472
+
1473
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1474
+ source=source
1475
+ )
1476
+ if error is not None:
1477
+ raise AssertionError(tests.common.most_underlying_messages(error))
1478
+ assert symbol_table is not None
1479
+
1480
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1481
+ some_property = some_class.properties[0]
1482
+ type_annotation = some_property.type_annotation
1483
+
1484
+ pickled_data = pickle.dumps(type_annotation)
1485
+ unpickled = pickle.loads(pickled_data)
1486
+
1487
+ self.assertIsInstance(unpickled, intermediate_types.TypeAnnotation)
1488
+
1489
+ def test_understood_method(self) -> None:
1490
+ source = textwrap.dedent(
1491
+ """\
1492
+ class Some_class:
1493
+ def some_method(self) -> None:
1494
+ pass
1495
+
1496
+ __version__ = "dummy"
1497
+ __xml_namespace__ = "https://dummy.com"
1498
+ """
1499
+ )
1500
+
1501
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1502
+ source=source
1503
+ )
1504
+ if error is not None:
1505
+ raise AssertionError(tests.common.most_underlying_messages(error))
1506
+ assert symbol_table is not None
1507
+
1508
+ some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
1509
+ some_method = some_class.methods[0]
1510
+
1511
+ pickled_data = pickle.dumps(some_method)
1512
+ unpickled = pickle.loads(pickled_data)
1513
+
1514
+ assert isinstance(unpickled, intermediate.UnderstoodMethod)
1515
+
1516
+ self.assertEqual(unpickled.name, "some_method")
1517
+
1518
+ def test_verification(self) -> None:
1519
+ source = textwrap.dedent(
1520
+ """\
1521
+ @verification
1522
+ def some_verification(x: int) -> bool:
1523
+ return x > 0
1524
+
1525
+ __version__ = "dummy"
1526
+ __xml_namespace__ = "https://dummy.com"
1527
+ """
1528
+ )
1529
+
1530
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1531
+ source=source
1532
+ )
1533
+ if error is not None:
1534
+ raise AssertionError(tests.common.most_underlying_messages(error))
1535
+ assert symbol_table is not None
1536
+
1537
+ verification = symbol_table.verification_functions[0]
1538
+
1539
+ pickled_data = pickle.dumps(verification)
1540
+ unpickled = pickle.loads(pickled_data)
1541
+
1542
+ assert isinstance(unpickled, intermediate.Verification)
1543
+
1544
+ self.assertEqual(unpickled.name, "some_verification")
1545
+
1546
+ def test_constant_set_of_enumeration_literals(self) -> None:
1547
+ source = textwrap.dedent(
1548
+ """\
1549
+ from enum import Enum
1550
+
1551
+ from aas_core_meta.marker import (
1552
+ constant_set
1553
+ )
1554
+
1555
+ class Some_enum(Enum):
1556
+ Literal1 = "lit1"
1557
+ Literal2 = "lit2"
1558
+
1559
+ Some_constant_set: Set[Some_enum] = constant_set(
1560
+ values=[
1561
+ Some_enum.Literal1
1562
+ ]
1563
+ )
1564
+
1565
+ __version__ = "dummy"
1566
+ __xml_namespace__ = "https://dummy.com"
1567
+ """
1568
+ )
1569
+
1570
+ symbol_table, error = tests.common.translate_source_to_intermediate(
1571
+ source=source
1572
+ )
1573
+ if error is not None:
1574
+ raise AssertionError(tests.common.most_underlying_messages(error))
1575
+ assert symbol_table is not None
1576
+
1577
+ some_constant_set = symbol_table.must_find_constant_set_of_enumeration_literals(
1578
+ Identifier("Some_constant_set")
1579
+ )
1580
+
1581
+ # Test before pickling
1582
+ original_id_set = some_constant_set.literal_id_set
1583
+ self.assertEqual(len(original_id_set), 1)
1584
+ self.assertIn(id(some_constant_set.literals[0]), original_id_set)
1585
+
1586
+ # Pickle and unpickle
1587
+ pickled_data = pickle.dumps(some_constant_set)
1588
+ unpickled = pickle.loads(pickled_data)
1589
+
1590
+ assert isinstance(unpickled, intermediate.ConstantSetOfEnumerationLiterals)
1591
+
1592
+ # Test after unpickling
1593
+ self.assertEqual(unpickled.name, "Some_constant_set")
1594
+ self.assertEqual(len(unpickled.literals), 1)
1595
+ self.assertEqual(unpickled.literals[0].name, "Literal1")
1596
+
1597
+ # Test that ID sets are rebuilt correctly
1598
+ new_id_set = unpickled.literal_id_set
1599
+ self.assertEqual(len(new_id_set), 1)
1600
+ self.assertIn(id(unpickled.literals[0]), new_id_set)
1601
+
1602
+
1603
+ def _to_lower_snake_case(cls_name: str) -> str:
1604
+ """
1605
+ Convert a class name from CamelCase to snake_case.
1606
+
1607
+ >>> _to_lower_snake_case("Enumeration")
1608
+ 'enumeration'
1609
+
1610
+ >>> _to_lower_snake_case("EnumerationLiteral")
1611
+ 'enumeration_literal'
1612
+
1613
+ >>> _to_lower_snake_case("ConstrainedPrimitive")
1614
+ 'constrained_primitive'
1615
+
1616
+ >>> _to_lower_snake_case("ConstructorArgumentOfClass")
1617
+ 'constructor_argument_of_class'
1618
+
1619
+ >>> _to_lower_snake_case("_ConstructorArgumentOfClass")
1620
+ 'constructor_argument_of_class'
1621
+ """
1622
+ s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", cls_name.lstrip("_"))
1623
+ return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
1624
+
1625
+
1626
+ class TestAssertions(unittest.TestCase):
1627
+ def test_coverage(self) -> None:
1628
+ """Assert that all classes from intermediate._types are covered in test methods."""
1629
+ all_classes = [] # type: List[str]
1630
+ for class_name, obj in inspect.getmembers(intermediate_types, inspect.isclass):
1631
+ if obj.__module__ == intermediate_types.__name__:
1632
+ all_classes.append(class_name)
1633
+
1634
+ expected_test_prefixes = [
1635
+ f"test_{_to_lower_snake_case(cls_name)}" for cls_name in all_classes
1636
+ ]
1637
+
1638
+ test_methods = [] # type: List[str]
1639
+ for method_name in dir(TestPickle):
1640
+ if method_name.startswith("test_") and callable(
1641
+ getattr(TestPickle, method_name)
1642
+ ):
1643
+ test_methods.append(method_name)
1644
+
1645
+ missing_tests = [] # type: List[str]
1646
+ for expected_prefix in expected_test_prefixes:
1647
+ found = any(
1648
+ test_method.startswith(expected_prefix) for test_method in test_methods
1649
+ )
1650
+ if not found:
1651
+ missing_tests.append(expected_prefix)
1652
+
1653
+ if len(missing_tests) > 0:
1654
+ missing_classes = []
1655
+ for prefix in missing_tests:
1656
+ assert prefix.startswith("test_") and len("test_") == 5
1657
+ snake_case_name = prefix[5:]
1658
+
1659
+ parts = snake_case_name.split("_")
1660
+ original_name = "".join(word.capitalize() for word in parts)
1661
+ missing_classes.append(original_name)
1662
+
1663
+ missing_tests_joined = ",\n".join(missing_tests)
1664
+
1665
+ raise AssertionError(
1666
+ f"Missing one or more test methods "
1667
+ f"in {TestPickle.__name__} for {len(missing_tests)} class(es):\n"
1668
+ f"{missing_tests_joined}"
1669
+ )
1670
+
1671
+ def test_getstate_setstate_consistency(self) -> None:
1672
+ class _PickableClass:
1673
+ """Represent a class which has pickle/unpickle methods."""
1674
+
1675
+ getstate: Final[Optional[ast.FunctionDef]]
1676
+ setstate: Final[Optional[ast.FunctionDef]]
1677
+ id_set_properties: Final[Sequence[str]]
1678
+
1679
+ @require(
1680
+ lambda getstate: not (getstate is not None)
1681
+ or getstate.name == "__getstate__"
1682
+ )
1683
+ @require(
1684
+ lambda setstate: not (setstate is not None)
1685
+ or setstate.name == "__setstate__"
1686
+ )
1687
+ def __init__(
1688
+ self,
1689
+ id_set_properties: Sequence[str],
1690
+ getstate: Optional[ast.FunctionDef] = None,
1691
+ setstate: Optional[ast.FunctionDef] = None,
1692
+ ) -> None:
1693
+ self.id_set_properties = id_set_properties
1694
+ self.getstate = getstate
1695
+ self.setstate = setstate
1696
+
1697
+ types_file = pathlib.Path(intermediate_types.__file__)
1698
+ source_code = types_file.read_text(encoding="utf-8")
1699
+
1700
+ tree = ast.parse(source_code)
1701
+
1702
+ class_map = {} # type: Dict[str, _PickableClass]
1703
+
1704
+ for node in ast.walk(tree):
1705
+ if isinstance(node, ast.ClassDef):
1706
+ id_set_properties = [] # type: List[str]
1707
+
1708
+ # NOTE (mristin):
1709
+ # We go through all type-annotated properties and pick all properties
1710
+ # with suffix ``*_id_set``. This will give us some guard rails to make
1711
+ # sure that we did not forget to pop/set these properties in
1712
+ # ``__getstate__`` and ``__setstate__``. However, there might be more
1713
+ # runtime properties which need checking. Eventually, though unlikely,
1714
+ # the suffix ``_id_set`` might be misleading, so then we have to add
1715
+ # white listing here.
1716
+ for item in node.body:
1717
+ if isinstance(item, ast.AnnAssign):
1718
+ if isinstance(item.target, ast.Name):
1719
+ property_name = item.target.id
1720
+ if property_name.endswith("_id_set"):
1721
+ id_set_properties.append(property_name)
1722
+
1723
+ getstate = None # type: Optional[ast.FunctionDef]
1724
+ setstate = None # type: Optional[ast.FunctionDef]
1725
+
1726
+ for item in node.body:
1727
+ if isinstance(item, ast.FunctionDef):
1728
+ if item.name == "__getstate__":
1729
+ getstate = item
1730
+
1731
+ elif item.name == "__setstate__":
1732
+ setstate = item
1733
+
1734
+ else:
1735
+ pass
1736
+
1737
+ if getstate is not None or setstate is not None:
1738
+ class_map[node.name] = _PickableClass(
1739
+ id_set_properties=id_set_properties,
1740
+ getstate=getstate,
1741
+ setstate=setstate,
1742
+ )
1743
+
1744
+ for class_name, cls in class_map.items():
1745
+ if cls.getstate is None and cls.setstate is None:
1746
+ continue
1747
+
1748
+ if cls.getstate is None and cls.setstate is not None:
1749
+ raise AssertionError(
1750
+ f"Unexpected missing __getstate__ when __setstate__ is specified "
1751
+ f"in the class {class_name!r}"
1752
+ )
1753
+
1754
+ if cls.getstate is not None and cls.setstate is None:
1755
+ raise AssertionError(
1756
+ f"Unexpected missing __setstate__ when __getstate__ is specified "
1757
+ f"in the class {class_name!r}"
1758
+ )
1759
+
1760
+ assert cls.getstate is not None and cls.setstate is not None
1761
+
1762
+ # NOTE (mristin):
1763
+ # We extract popped attributes from ``__getstate__``.
1764
+ popped_attrs = [] # type: List[str]
1765
+
1766
+ for node in ast.walk(cls.getstate):
1767
+ if (
1768
+ isinstance(node, ast.Call)
1769
+ and isinstance(node.func, ast.Attribute)
1770
+ and node.func.attr == "pop"
1771
+ and isinstance(node.func.value, ast.Name)
1772
+ and node.func.value.id == "state"
1773
+ ):
1774
+ if (
1775
+ len(node.args) > 0
1776
+ and isinstance(node.args[0], ast.Constant)
1777
+ and isinstance(node.args[0].value, str)
1778
+ ):
1779
+ popped_attrs.append(node.args[0].value)
1780
+
1781
+ setattr_attrs = [] # type: List[str]
1782
+
1783
+ for node in ast.walk(cls.setstate):
1784
+ if (
1785
+ isinstance(node, ast.Call)
1786
+ and isinstance(node.func, ast.Name)
1787
+ and node.func.id == "setattr"
1788
+ ):
1789
+ # NOTE (mristin):
1790
+ # The second argument is the name of the attribute.
1791
+ if (
1792
+ len(node.args) >= 2
1793
+ and isinstance(node.args[0], ast.Name)
1794
+ and node.args[0].id == "self"
1795
+ and isinstance(node.args[1], ast.Constant)
1796
+ and isinstance(node.args[1].value, str)
1797
+ ):
1798
+ setattr_attrs.append(node.args[1].value)
1799
+
1800
+ if set(popped_attrs) != set(setattr_attrs):
1801
+ raise AssertionError(
1802
+ f"In class {class_name!r}, there is a mismatch between "
1803
+ f"popped attributes in __getstate__: {sorted(popped_attrs)}, "
1804
+ f"and setattr attributes in __setstate__: {sorted(setattr_attrs)}"
1805
+ )
1806
+
1807
+ # NOTE (mristin):
1808
+ # We check that all properties with suffix ``_id_set`` are popped in
1809
+ # ``__getstate__`` and, consequently, set in ``__setstate__``.
1810
+ id_set_properties_set = set(cls.id_set_properties)
1811
+ popped_attrs_set = set(popped_attrs)
1812
+ if not id_set_properties_set.issubset(popped_attrs_set):
1813
+ missing_from_popped = id_set_properties_set - popped_attrs_set
1814
+ raise AssertionError(
1815
+ f"In class {class_name!r}, the following properties "
1816
+ f"containing runtime ID sets are not being popped in __getstate__: "
1817
+ f"{sorted(missing_from_popped)}."
1818
+ )
1819
+
1820
+ if len(cls.getstate.body) < 2:
1821
+ raise AssertionError(
1822
+ f"Class {class_name}: __getstate__ should have at least 2 statements"
1823
+ )
1824
+
1825
+ # First statement should be state = self.__dict__.copy().
1826
+ getstate_first_stmt = cls.getstate.body[0]
1827
+ if not (
1828
+ isinstance(getstate_first_stmt, ast.Assign)
1829
+ and len(getstate_first_stmt.targets) == 1
1830
+ and isinstance(getstate_first_stmt.targets[0], ast.Name)
1831
+ and getstate_first_stmt.targets[0].id == "state"
1832
+ ):
1833
+ raise AssertionError(
1834
+ f"In class {class_name!r}, the method __getstate__ should start "
1835
+ f"with 'state = ...'"
1836
+ )
1837
+
1838
+ # Last statement should be return state.
1839
+ getstate_last_stmt = cls.getstate.body[-1]
1840
+ if not (
1841
+ isinstance(getstate_last_stmt, ast.Return)
1842
+ and isinstance(getstate_last_stmt.value, ast.Name)
1843
+ and getstate_last_stmt.value.id == "state"
1844
+ ):
1845
+ raise AssertionError(
1846
+ f"In class {class_name!r}, the method __getstate__ should end "
1847
+ f"with 'return state'"
1848
+ )
1849
+
1850
+ if len(cls.setstate.body) == 0:
1851
+ raise AssertionError(
1852
+ f"In class {class_name!r}, the method __setstate__ should have "
1853
+ f"at least 1 statement"
1854
+ )
1855
+
1856
+ # First statement should be self.__dict__.update(state).
1857
+ setstate_first_stmt = cls.setstate.body[0]
1858
+ if not (
1859
+ isinstance(setstate_first_stmt, ast.Expr)
1860
+ and isinstance(setstate_first_stmt.value, ast.Call)
1861
+ and isinstance(setstate_first_stmt.value.func, ast.Attribute)
1862
+ and setstate_first_stmt.value.func.attr == "update"
1863
+ ):
1864
+ raise AssertionError(
1865
+ f"In class {class_name!r}, the method __setstate__ should start "
1866
+ f"with 'self.__dict__.update(state)'"
1867
+ )
1868
+
1869
+
1870
+ if __name__ == "__main__":
1871
+ unittest.main()