-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtest_core.py
2173 lines (1629 loc) · 88.4 KB
/
test_core.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import unittest
import sys
import os
from os.path import join as pjoin
from typing import Dict, List, Union
from packaging import version
import rdflib
# noinspection PyUnresolvedReferences
from ipydex import IPS, activate_ips_on_exception, set_trace # noqa
import pyirk as p
import pyirk.visualization as visualization
import pyirk.io
from pyirk.auxiliary import uri_set
import git
import pyirk.reportgenerator as rgen
from .settings import (
IRK_ROOT_DIR,
TEST_DATA_DIR1,
TEST_DATA_PATH2,
TEST_DATA_PATH_MA,
TEST_DATA_PATH3,
TEST_DATA_PATH_ZEBRA_BASE_DATA,
TEST_DATA_PATH_ZEBRA02,
TEST_MOD_NAME,
# TEST_ACKREP_DATA_FOR_UT_PATH,
TEST_BASE_URI,
WRITE_TMP_FILES,
HousekeeperMixin,
)
# todo apparently, this does not effect the tests, i.e. test_e04__overloaded_math_operators
# if not os.environ.get("PYIRK_DISABLE_CONSISTENCY_CHECKING", "").lower() == "true":
# p.cc.enable_consistency_checking()
class Test_00_Core(HousekeeperMixin, unittest.TestCase):
def test_a1__dependencies(self):
# this tests checks some dependencies which are prone to cause problems (e.g. due to recent api-changes)
pydantic_version = version.parse(p.pydantic.__version__)
self.assertGreaterEqual(pydantic_version, version.parse("2.4.2"))
def test_b1__process_key_str(self):
res = p.process_key_str("I1")
self.assertEqual(res.prefix, None)
self.assertEqual(res.short_key, "I1")
self.assertEqual(res.label, None)
res = p.process_key_str("I000__test_label", check=False)
self.assertEqual(res.prefix, None)
self.assertEqual(res.short_key, "I000")
self.assertEqual(res.label, "test_label")
res = p.process_key_str("some_prefix__I000", check=False, resolve_prefix=False)
self.assertEqual(res.prefix, "some_prefix")
self.assertEqual(res.short_key, "I000")
self.assertEqual(res.label, None)
res = p.process_key_str("some_prefix__I000__test_label", check=False, resolve_prefix=False)
self.assertEqual(res.prefix, "some_prefix")
self.assertEqual(res.short_key, "I000")
self.assertEqual(res.label, "test_label")
with self.assertRaises(p.UnknownPrefixError):
res = p.process_key_str("some_prefix__I000__test_label", check=False, resolve_prefix=True)
with self.assertRaises(p.aux.InvalidGeneralKeyError):
res = p.process_key_str("some_prefix_literal_value", check=False)
res = p.process_key_str("some_prefix__I000['test_label']", check=False, resolve_prefix=False)
self.assertEqual(res.prefix, "some_prefix")
self.assertEqual(res.short_key, "I000")
self.assertEqual(res.label, "test_label")
res = p.process_key_str('some_prefix__I000["test_label"]', check=False, resolve_prefix=False)
self.assertEqual(res.prefix, "some_prefix")
self.assertEqual(res.short_key, "I000")
self.assertEqual(res.label, "test_label")
with self.assertRaises(p.aux.InvalidGeneralKeyError):
res = p.process_key_str("some_prefix__I000['missing bracket'", check=False)
with self.assertRaises(p.aux.InvalidGeneralKeyError):
res = p.process_key_str("some_prefix__I000[missing quotes]", check=False)
with self.assertRaises(p.aux.InvalidGeneralKeyError):
res = p.process_key_str("some_prefix__I000__double_label_['redundant']", check=False)
def test_b2__uri_context_manager(self):
"""
Test defined behavior of errors occur in uri_context
:return:
"""
self.assertEqual(len(p.core._uri_stack), 0)
try:
with p.uri_context(uri=TEST_BASE_URI):
raise ValueError
except ValueError:
pass
self.assertEqual(len(p.core._uri_stack), 0)
self.assertEqual(len(p.ds.entities_created_in_mod), 1)
L1 = len(p.ds.items)
L2 = len(p.ds.relations)
L3 = len(p.ds.statement_uri_map)
try:
_ = p.irkloader.load_mod_from_path(pjoin(TEST_DATA_DIR1, "tmod0_with_errors.py"), prefix="tm0")
except ValueError:
pass
# assert that no entities remain in the data structures
self.assertEqual(len(p.ds.entities_created_in_mod), 1)
self.assertEqual(L1, len(p.ds.items))
self.assertEqual(L2, len(p.ds.relations))
self.assertEqual(L3, len(p.ds.statement_uri_map))
self.assertEqual(len(p.core._uri_stack), 0)
def test_b3__key_manager(self):
p.KeyManager.instance = None
km = p.KeyManager(minval=100, maxval=105)
self.assertEqual(km.key_reservoir, [103, 101, 100, 104, 102])
k = km.pop()
self.assertEqual(k, 102)
k = km.pop()
self.assertEqual(k, 104)
self.assertEqual(km.key_reservoir, [103, 101, 100])
def test_b4__uri_attr_of_entities(self):
self.assertEqual(p.I1.uri, f"{p.BUILTINS_URI}#I1")
self.assertEqual(p.R1.uri, f"{p.BUILTINS_URI}#R1")
with self.assertRaises(p.aux.EmptyURIStackError):
itm = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item")
with p.uri_context(uri=TEST_BASE_URI):
itm = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item")
rel = p.create_relation(key_str=p.pop_uri_based_key("R"), R1="unit test relation")
self.assertEqual(itm.uri, f"{TEST_BASE_URI}#{itm.short_key}")
self.assertEqual(rel.uri, f"{TEST_BASE_URI}#{rel.short_key}")
def test_c1__load_multiple_modules(self):
mod1 = p.irkloader.load_mod_from_path(pjoin(TEST_DATA_DIR1, "tmod1.py"), prefix="tm1")
# test recursive module loading
self.assertEqual(mod1.foo_mod.__URI__, "irk:/pyirk/testmodule3")
# test validity of R2000 statements (created in tmod1 with a relation from tmod3)
stm1, stm2 = mod1.I1000.get_relations("bar__R2000")
self.assertEqual(stm1.object, 42)
self.assertEqual(stm2.object, 23)
# test uri_contexts of R2000 statements
self.assertTrue(stm1.uri.startswith(mod1.__URI__))
self.assertTrue(stm2.uri.startswith(mod1.__URI__))
def test_c02__exception_handling(self):
os.environ["PYIRK_TRIGGER_TEST_EXCEPTION"] = "True"
with self.assertRaises(p.aux.ExplicitlyTriggeredTestException):
mod1 = p.irkloader.load_mod_from_path(pjoin(TEST_DATA_DIR1, "tmod1.py"), prefix="tm1")
# this was a bug: if the module is loaded for the second time exception is not handled correctly
with self.assertRaises(p.aux.ExplicitlyTriggeredTestException):
mod1 = p.irkloader.load_mod_from_path(pjoin(TEST_DATA_DIR1, "tmod1.py"), prefix="tm1")
os.environ.pop("PYIRK_TRIGGER_TEST_EXCEPTION")
@unittest.skipIf(os.environ.get("CI"), "Skipping directory structure tests on CI")
class Test_01_Core(HousekeeperMixin, unittest.TestCase):
def test_a01__directory_structure(self):
pyirk_dir = pjoin(IRK_ROOT_DIR, "pyirk-core")
django_gui_dir = pjoin(IRK_ROOT_DIR, "pyirk-django")
self.assertTrue(os.path.isdir(pyirk_dir))
if not os.path.isdir(django_gui_dir):
print("unexpected: {django_gui_dir} not found")
def test_a01__test_independence(self):
"""
The first test ensures, that TestCases do not influence each other
"""
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
self.tearDown()
# after tearing down there should be no i32 instances left
i32_instance_rels = p.I32["evaluated mapping"].get_inv_relations("R4__is_instance_of")
self.assertEqual(len(i32_instance_rels), 0)
builtin_entity_uris = set(p.ds.entities_created_in_mod[p.BUILTINS_URI])
builtin_stm_uris = set(p.ds.stms_created_in_mod[p.BUILTINS_URI])
available_item_keys = set(p.ds.items.keys())
available_relation_keys = set(p.ds.relations.keys())
available_statement_keys = set(p.ds.statement_uri_map.keys())
available_relation_statement_keys = set(p.ds.relation_statements.keys())
diff1 = available_item_keys.difference(builtin_entity_uris)
diff2 = available_relation_keys.difference(builtin_entity_uris)
diff3 = available_statement_keys.difference(builtin_stm_uris)
diff4 = available_relation_statement_keys.difference(builtin_entity_uris)
self.assertEqual(len(diff1), 0)
self.assertEqual(len(diff2), 0)
self.assertEqual(len(diff3), 0)
self.assertEqual(len(diff4), 0)
def test_a03_tear_down(self):
"""
test if tear_down of TestClass works properly
:return:
"""
# ensure that builtins are loaded
self.assertGreater(len(p.ds.items), 40)
self.assertGreater(len(p.ds.relations), 40)
self.assertGreater(len(p.ds.statement_uri_map), 300)
# ensure that no residuals are left from last test
non_builtin_stms = [k for k in p.ds.statement_uri_map.keys() if not k.startswith(p.BUILTINS_URI)]
self.assertEqual(len(non_builtin_stms), 0)
non_builtin_entities = [k for k in p.ds.items.keys() if not k.startswith(p.BUILTINS_URI)]
non_builtin_entities += [k for k in p.ds.relations.keys() if not k.startswith(p.BUILTINS_URI)]
self.assertEqual(len(non_builtin_entities), 0)
# noinspection PyUnresolvedReferences
# (above noinspection is necessary because of the @-operator which is undeclared for strings)
def test_b00__core1_basics(self):
mod1 = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
self.assertEqual(mod1.ma.I3749.R1.value, "Cayley-Hamilton theorem")
def_eq_item = mod1.I6886.R6__has_defining_mathematical_relation
self.assertEqual(def_eq_item.R4__is_instance_of, p.I18["mathematical expression"])
self.assertEqual(def_eq_item.R24__has_LaTeX_string, r"$\dot x = f(x, u)$")
mod_uri = p.ds.uri_prefix_mapping.b["ct"]
p.unload_mod(mod_uri)
def test_b01_builtins1(self):
"""
Test the mechanism to endow the Entity class with custom methods (on class and on instance level)
:return:
"""
# class level
def example_func(slf, a):
return f"{slf.R1.value}--{a}"
p.Entity.add_method_to_class(example_func)
res = p.I12.example_func("test")
self.assertEqual("mathematical object--test", res)
# instance level
# Note: this creates items with keys which might conflict with recently added keys to builtin entities
# explicitly unlinking them at the end
with p.uri_context(uri=TEST_BASE_URI):
itm = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item")
itm2 = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item2")
def example_func2(slf, a):
return f"{slf.R1.value}::{a}"
itm.add_method(example_func2)
res2 = itm.example_func2(1234)
self.assertEqual("unit test item::1234", res2)
self.assertIsInstance(itm2, p.Entity)
# ensure that this method is not available to generic other instances of Entity
with self.assertRaises(AttributeError):
itm2.example_func2(1234)
def test_a01b_add_method_recursively(self):
"""
ensure inheritance of custom methods works regardless of declaration order
"""
def test_func(slf):
return slf.R1.value
with p.uri_context(uri=TEST_BASE_URI):
itm1 = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item1")
itm2 = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item2")
itm3 = p.create_item(key_str=p.pop_uri_based_key("I"), R1="unit test item3")
itm2.set_relation(p.R3["is subclass of"], itm1)
itm3.set_relation(p.R4["is instance of"], itm2)
itm1.add_method(test_func)
self.assertEqual(itm2.test_func(), "unit test item2")
self.assertEqual(itm3.test_func(), "unit test item3")
# TODO: trigger loading of unittest version of ocse via envvar
def test_a02__load_settings(self):
"""
ensure that the default settingsfile is loaded correctly
"""
# this is a variable which should be present in every pyirkconf file
conf = p.settings.CONF
# self.assertTrue(len(conf) != 0)
self.assertTrue(len(conf) >= 0)
def test_b02_builtins2(self):
rel = p.R65
self.assertIsInstance(rel.R1, p.Literal)
# do not allow Literal here
self.assertEqual(type(rel.R1.value), str)
k = "R65__allows_alternative_functional_value"
pk = p.process_key_str(k)
def test_b03_get_instances(self):
"""
test the generation of direct and indirect instance lists
"""
classes: list[p.Item] = p.get_direct_instances_of(p.I2["Metaclass"])
res = {}
for cl in classes:
res[repr(cl)] = len(p.get_all_instances_of(cl))
all_numbers1 = p.get_all_instances_of(p.I34["complex number"])
# no number has been defined yet
self.assertEqual(all_numbers1, [])
# now define numbers and test class structure
with p.uri_context(uri=TEST_BASE_URI):
i1 = p.instance_of(p.I39["positive integer"])
i2 = p.instance_of(p.I38["non-negative integer"])
i3 = p.instance_of(p.I37["integer number"])
q1 = p.instance_of(p.I36["rational number"])
r1 = p.instance_of(p.I35["real number"])
c1 = p.instance_of(p.I34["complex number"])
expected_numbers2 = set((i1, i2, i3, q1, r1, c1))
all_numbers2 = p.get_all_instances_of(p.I34["complex number"])
self.assertEqual(set(all_numbers2), expected_numbers2)
expected_numbers3 = set((i1, i2, i3, q1))
all_numbers3 = p.get_all_instances_of(p.I36["rational number"])
self.assertEqual(set(all_numbers3), expected_numbers3)
self.assertEqual(p.get_direct_instances_of(p.I36["rational number"]), [q1])
expected_numbers4 = set((i1, i2))
all_numbers4 = p.get_all_instances_of(p.I38["non-negative integer"])
self.assertEqual(set(all_numbers4), expected_numbers4)
self.assertEqual(p.get_direct_instances_of(p.I38["non-negative integer"]), [i2])
def test_b04_get_subclasses(self):
"""
test the generation of direct and indirect subclass lists
"""
cls_item = p.I34["complex number"]
direct_subclasses = cls_item.get_inv_relations("R3__is_subclass_of", return_subj=True)
all_subclasses = p.get_all_subclasses_of(cls_item)
self.assertEqual(direct_subclasses, [p.I35["real number"]])
expected_subclasses = set(
(
p.I35["real number"],
p.I36["rational number"],
p.I37["integer number"],
p.I38["non-negative integer"],
p.I39["positive integer"],
)
)
self.assertEqual(set(all_subclasses), expected_subclasses)
def test_c01__ct_loads_math(self):
"""
test if the control_theory module successfully loads the math module
:return:
"""
mod1 = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
self.assertIn("ma", p.ds.uri_prefix_mapping.b)
itm1 = p.ds.get_entity_by_key_str("ma__I5000__scalar_zero")
self.assertEqual(itm1, mod1.ma.I5000["scalar zero"])
def test_c03__nontrivial_metaclasses(self):
with p.uri_context(uri=TEST_BASE_URI):
i1 = p.instance_of(p.I34["complex number"])
self.assertTrue(i1.R4, p.I34)
def test_c04__evaluated_mapping(self):
res = p.ds.statements.get("S6229")
self.assertIsNone(res)
ct = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
with p.uri_context(uri=TEST_BASE_URI):
poly1 = p.instance_of(ct.ma.I4239["abstract monovariate polynomial"])
# test that an arbitrary item is *not* callable
self.assertRaises(TypeError, ct.ma.I2738["field of complex numbers"], 0)
# test that some special items are callable (note that its parent class is a subclass of one which has
# a _custom_call-method defined)
with p.uri_context(uri=TEST_BASE_URI):
# this creates new items and thus must be executed inside a context
res = poly1(0)
self.assertEqual(res.R4__is_instance_of, p.I32["evaluated mapping"])
with p.uri_context(uri=TEST_BASE_URI):
x = p.instance_of(p.I35["real number"])
s1 = ct.ma.I5807["sign"](x)
s2 = ct.ma.I5807["sign"](x)
self.assertTrue(s1 is s2)
def test_c05__evaluated_mapping2(self):
mod1 = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
with p.uri_context(uri=TEST_BASE_URI):
h = p.instance_of(mod1.ma.I9923["scalar field"])
f = p.instance_of(mod1.ma.I9841["vector field"])
x = p.instance_of(mod1.ma.I1168["point in state space"])
Lderiv = mod1.I1347["Lie derivative of scalar field"]
# this creates a new item (and thus must be executed with a non-empty uri stack, i.e. within this context)
h2 = Lderiv(h, f, x)
self.assertEqual(h2.R4__is_instance_of, mod1.ma.I9923["scalar field"])
arg_tup = h2.R36__has_argument_tuple
self.assertEqual(arg_tup.R4__is_instance_of, p.I33["tuple"])
elements = arg_tup.R39__has_element
self.assertEqual(tuple(elements), (h, f, x))
def test_c06__tuple(self):
data = (10, 11, 12, 13, p.I1, "some string")
with self.assertRaises(p.aux.EmptyURIStackError):
tup = p.new_tuple(*data)
with p.uri_context(uri=TEST_BASE_URI):
tup = p.new_tuple(*data)
self.assertEqual(tup.R4__is_instance_of, p.I33["tuple"])
self.assertEqual(tup.R38__has_length, 6)
# TODO: non functional relations should return a tuple not a list?
res = tup.R39__has_element
self.assertEqual(data, tuple(res))
def test_c07__scope_vars(self):
# this tests for a bug with labels of scope vars
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
def_itm = p.ds.get_entity_by_key_str("ma__I9907__definition_of_square_matrix")
matrix_instance = def_itm.M
self.assertEqual(matrix_instance.R1.value, "M")
@unittest.expectedFailure
def test_c07b__nested_scopes_of_propositions(self):
"""
Test existentially and universally quantified conditions as nested scopes in scopes of propositions/definitions
"""
with p.uri_context(uri=TEST_BASE_URI):
I7324 = p.create_item(
R1__has_label="definition of something",
R4__is_instance_of=p.I20["mathematical definition"],
)
my_set = p.instance_of(p.I13["mathematical set"])
my_prop = p.instance_of(p.I54["mathematical property"])
with I7324["definition of something"].scope("setting") as cm:
x = cm.new_var(x=p.instance_of(p.I39["positive integer"]))
y = cm.new_var(y=p.instance_of(p.I39["positive integer"]))
with I7324["definition of something"].scope("premise") as cm:
with cm.universally_quantified() as cm2:
cm2.add_condition_statement(cm.x, p.R15["is element of"], my_set)
cm2.add_condition_statement(cm.y, p.R15["is element of"], my_set)
# note: the meaning of this equation is pointless, we just test the implementation of subscopes
cm2.new_equation(lhs=cm.x, rhs=cm.y)
with I7324["definition of something"].scope("assertion") as cm:
cm.new_rel(cm.x, p.R16["has property"], my_prop)
cm.new_rel(cm.y, p.R16["has property"], my_prop)
# also pointless direct meaning, only to test contexts
with cm.existentially_quantified() as cm2:
z = cm2.new_condition_var(z=p.instance_of(p.I39["positive integer"]))
cm2.add_condition_statement(cm2.z, p.R15["is element of"], my_set)
cm2.add_condition_statement(cm.y, p.R15["is element of"], my_set)
cm2.add_condition_math_relation(cm2.z, "<", cm.x)
cm2.new_math_relation(cm2.z, ">", cm.y)
# universally quantified scope
scp_prem = I7324.get_subscopes()[1]
prem_sub_scopes = scp_prem.get_subscopes()
self.assertEqual(len(prem_sub_scopes), 1)
uq_scp = prem_sub_scopes[0]
self.assertEqual(uq_scp.R64__has_scope_type, "UNIV_QUANT")
# check the condition
cond_sc = uq_scp.get_subscopes()[0]
cond_stms = cond_sc.get_statements_for_scope()
stm1: p.Statement = cond_stms[0]
self.assertEqual(stm1.subject, x)
self.assertEqual(stm1.predicate, p.R15["is element of"])
self.assertEqual(stm1.object, my_set)
# check the actual statement (which is an equation)
(stm1,) = uq_scp.get_statements_for_scope()
self.assertEqual(stm1.subject, x)
self.assertEqual(stm1.predicate, p.R31["is in mathematical relation with"])
self.assertEqual(stm1.object, y)
proxy_item = stm1.get_first_qualifier_obj_with_rel("R34__has_proxy_item")
self.assertEqual(proxy_item.R4__is_instance_of, p.I23["equation"])
self.assertEqual(proxy_item.R26__has_lhs, x)
self.assertEqual(proxy_item.R27__has_rhs, y)
# existentially quantified scope
scp_asstn = I7324.get_subscopes()[2]
self.assertEqual(len(scp_asstn.get_subscopes()), 1)
ex_scp = scp_asstn.get_subscopes()[0]
self.assertEqual(ex_scp.R64__has_scope_type, "EXIS_QUANT")
# check the conditions
# TODO fix this after (broke due to removal of condition_cm)
cond_sc = ex_scp.get_subscopes()[0]
cond_itms = cond_sc.get_items_for_scope()
self.assertEqual(len(cond_itms), 2)
self.assertIn(z, cond_itms)
# apart from z there is also the cond_proxy_item, see below
cond_stms = cond_sc.get_statements_for_scope()
self.assertEqual(len(cond_stms), 3)
stm1: p.Statement = cond_stms[0]
self.assertEqual(stm1.subject, z)
self.assertEqual(stm1.predicate, p.R15["is element of"])
self.assertEqual(stm1.object, my_set)
stm3: p.Statement = cond_stms[2]
self.assertEqual(stm3.subject, z)
self.assertEqual(stm3.predicate, p.R31["is in mathematical relation with"])
self.assertEqual(stm3.object, x)
cond_proxy_item = stm3.get_first_qualifier_obj_with_rel("R34__has_proxy_item")
self.assertIn(cond_proxy_item, cond_itms)
self.assertEqual(cond_proxy_item.R4__is_instance_of, p.I29["less-than-relation"])
self.assertEqual(cond_proxy_item.R26__has_lhs, z)
self.assertEqual(cond_proxy_item.R27__has_rhs, x)
# check the actual statement (which is an equation)
(stm1,) = ex_scp.get_statements_for_scope()
self.assertEqual(stm1.subject, z)
self.assertEqual(stm1.predicate, p.R31["is in mathematical relation with"])
self.assertEqual(stm1.object, y)
proxy_item = stm1.get_first_qualifier_obj_with_rel("R34__has_proxy_item")
self.assertEqual(proxy_item.R4__is_instance_of, p.I28["greater-than-relation"])
self.assertEqual(proxy_item.R26__has_lhs, z)
self.assertEqual(proxy_item.R27__has_rhs, y)
def test_c07c__boolean_subscopes(self):
"""
Test that `OR`, `AND` and `NOT` subscopes can be used.
"""
with p.uri_context(uri=TEST_BASE_URI):
I7000 = p.create_item(
R1__has_label="definition of countable",
R4__is_instance_of=p.I20["mathematical definition"],
)
finite = p.instance_of(p.I54["mathematical property"])
countably_infinite = p.instance_of(p.I54["mathematical property"])
countable = p.instance_of(p.I54["mathematical property"])
with I7000["definition of countable"].scope("setting") as cm:
cm.new_var(generic_set=p.instance_of(p.I13["mathematical set"]))
with I7000["definition of countable"].scope("premise") as cm:
with cm.OR() as cm2:
cm2.add_condition_statement(cm.generic_set, p.R16["has property"], finite)
cm2.add_condition_statement(cm.generic_set, p.R16["has property"], countably_infinite)
with I7000["definition of countable"].scope("assertion") as cm:
cm.new_rel(cm.generic_set, p.R16["has property"], countable)
# now test AND
I7100 = p.create_item(
R1__has_label="definition of positive integer",
R4__is_instance_of=p.I20["mathematical definition"],
)
cm: p.builtin_entities._proposition__CM
with I7100["definition of positive integer"].scope("setting") as cm:
cm.new_var(i1=p.instance_of(p.I37["integer number"]))
with I7100["definition of positive integer"].scope("premise") as cm:
with cm.AND() as cm2:
# Note, this cumbersome way to express i > 0 serves to use AND-relation.
cm2.add_condition_math_relation(cm.i1, ">=", 0)
cm2.add_condition_math_relation(cm.i1, "!=", 0)
with I7100["definition of positive integer"].scope("assertion") as cm:
cm.new_rel(cm.i1, p.R30["is secondary instance of"], p.I39["positive integer"])
# now test NOT
I7200 = p.create_item(
R1__has_label="definition of non-negative integer",
R4__is_instance_of=p.I20["mathematical definition"],
)
cm: p.builtin_entities._proposition__CM
with I7200["definition of non-negative integer"].scope("setting") as cm:
cm.new_var(i1=p.instance_of(p.I37["integer number"]))
with I7200["definition of non-negative integer"].scope("premise") as cm:
with cm.NOT() as cm2:
# Note, this cumbersome way to express i >= 0 serves to use NOT-relation.
cm2.add_condition_math_relation(cm.i1, "<", 0)
with I7200["definition of non-negative integer"].scope("assertion") as cm:
cm.new_rel(cm.i1, p.R30["is secondary instance of"], p.I38["non-negative integer"])
def test_c07d__nested_boolean_scopes(self):
ct = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
with p.uri_context(uri=TEST_BASE_URI):
I0100 = p.create_item(
R1__has_label="test-region in complex plane",
R4__is_instance_of=p.I13["mathematical set"],
R14__is_subset_of=ct.ma.I2738["field of complex numbers"],
)
I0101 = p.create_item(
R1__has_label="definition test-region in complex plane",
R4__is_instance_of=p.I20["mathematical definition"],
)
with I0101["definition test-region in complex plane"].scope("setting") as cm:
cm.new_var(z=p.instance_of(p.I34["complex number"]))
# z = x + 1j*y
cm.new_var(x=ct.ma.I5005["real part"](cm.z))
cm.new_var(y=ct.ma.I5006["imaginary part"](cm.z))
# the test-region is consists of three parts:
# - two axis-aligned polyhedral sets:
# - (x > 10, y > 20)
# - (x < -10, y < -20)
# - the real axis (y = 0)
with I0101["definition test-region in complex plane"].scope("premise") as cm:
with cm.OR() as cm2:
with cm2.AND() as cm2a:
cm2a.new_math_relation(cm.x, ">", 10)
cm2a.new_math_relation(cm.y, ">", 20)
with cm2.AND() as cm2b:
cm2b.new_math_relation(cm.x, "<", -10)
cm2b.new_math_relation(cm.y, "<", -20)
cm2.new_math_relation(cm.y, "==", 0)
with I0101["definition test-region in complex plane"].scope("assertion") as cm:
cm.new_rel(cm.z, p.R15["is element of"], I0100["test-region in complex plane"])
def test_c07q__scope_copying(self):
"""
test to copy statements from one scope to another
"""
ct = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
with p.uri_context(uri=TEST_BASE_URI):
I0111 = p.create_item(
R1__has_label="definition of something",
R4__is_instance_of=p.I20["mathematical definition"],
)
my_set = p.instance_of(p.I13["mathematical set"])
my_prop = p.instance_of(p.I54["mathematical property"])
# create some variables and relations
with I0111["definition of something"].scope("setting") as cm:
x = cm.new_var(x=p.instance_of(p.I39["positive integer"]))
y = cm.new_var(y=p.instance_of(p.I39["positive integer"]))
z = cm.new_var(z=p.instance_of(p.I39["positive integer"]))
cm.new_rel(x, p.R16["has property"], my_prop)
V = cm.new_var(V=p.instance_of(ct.ma.I9923["scalar field"]))
f = cm.new_var(f=p.instance_of(ct.ma.I9841["vector field"]))
LfV = cm.new_var(LfV=ct.I1347["Lie derivative of scalar field"](V, f, x))
# TODO: this does not occur in I0111_setting at all (!!)
with p.ImplicationStatement() as imp1:
imp1.antecedent_relation(lhs=x, rsgn="==", rhs=y)
imp1.consequent_relation(lhs=y, rsgn=">=", rhs=x)
I0111_setting = I0111["definition of something"].get_subscope("setting")
self.assertEqual(I0111_setting.R4__is_instance_of, p.I16["scope"])
# create a new definition and copy statements from the old one
I0222 = p.create_item(
R1__has_label="definition of something different",
R4__is_instance_of=p.I20["mathematical definition"],
)
with I0222["definition of something different"].scope("setting") as cm:
cm.copy_from(I0111_setting)
I0222_setting = I0222["definition of something different"].get_subscope("setting")
# stms = I0222_setting.get_inv_relations("R20__has_defining_scope")
stm_subjects = I0222_setting.get_inv_relations("R20__has_defining_scope", return_subj=True)
x2, y2, z2, V2, f2, LfV2 = stm_subjects[:6]
labels = [obj.R1.value for obj in stm_subjects[:3]]
self.assertEqual(labels, ["x", "y", "z"])
self.assertNotEqual(x.uri, x2.uri)
# relation statement are treated last
rel_stm = stm_subjects[-1]
self.assertIsInstance(rel_stm, p.Statement)
self.assertEqual(rel_stm.relation_tuple, (x2, p.R16["has property"], my_prop))
# TODO: test that the arguments of LfV are the new objects V2, f2, x2
args1 = LfV.get_arguments()
args2 = LfV2.get_arguments()
self.assertEqual(len(args1), len(args2))
self.assertEqual(args2, [V2, f2, x2])
def test_c08__relations_with_sequence_as_argument(self):
with p.uri_context(uri=TEST_BASE_URI):
Ia001 = p.create_item(R1__has_label="test item")
# check that assigning sequences is not allowed
with self.assertRaises(TypeError):
Ia001.set_relation(p.R5["is part of"], [p.I4["Mathematics"], p.I5["Engineering"]])
with p.uri_context(uri=TEST_BASE_URI):
# check that assigning sequences is possible with explicit method.
Ia001.set_multiple_relations(p.R5["is part of"], [p.I4["Mathematics"], p.I5["Engineering"]])
rel_objs = Ia001.get_relations("R5", return_obj=True)
self.assertEqual(rel_objs, [p.I4, p.I5])
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
itm = p.ds.get_entity_by_key_str("ct__I4466__Systems_Theory")
# construction: R5__is_part_of=[p.I4["Mathematics"], p.I5["Engineering"]]
res = itm.R5
self.assertEqual(len(res), 2)
self.assertIn(p.I4["Mathematics"], res)
self.assertIn(p.I5["Engineering"], res)
def test_c09__is_instance_of_generalized_metaclass(self):
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
itm1 = p.ds.get_entity_by_key_str("I2__Metaclass")
itm2 = p.ds.get_entity_by_key_str("I12__mathematical_object")
itm3 = p.ds.get_entity_by_key_str("ma__I4239__abstract_monovariate_polynomial")
# metaclass could be considered as an instance of itself because metaclasses are allowed to have
# subclasses and instances (which is both true for I2__metaclass)
self.assertTrue(p.allows_instantiation(itm1))
self.assertTrue(p.allows_instantiation(itm2))
self.assertTrue(p.allows_instantiation(itm3))
with p.uri_context(uri=TEST_BASE_URI):
# itm3 is a normal class -> itm4 is not allowed to have instances (itm4 is no metaclass-instance)
itm4 = p.instance_of(itm3)
self.assertFalse(p.allows_instantiation(itm4))
def test_c09a__is_subclass_of(self):
self.assertTrue(p.is_subclass_of(p.I39["positive integer"], p.I38["non-negative integer"]))
self.assertTrue(p.is_subclass_of(p.I39["positive integer"], p.I37["integer number"]))
self.assertTrue(p.is_subclass_of(p.I39["positive integer"], p.I35["real number"]))
with self.assertRaises(p.aux.TaxonomicError):
p.is_subclass_of(p.I39["positive integer"], p.I1["general item"])
self.assertFalse(p.is_subclass_of(p.I35["real number"], p.I39["positive integer"]))
self.assertFalse(p.is_subclass_of(p.I35["real number"], p.I35["real number"]))
self.assertTrue(p.is_subclass_of(p.I35["real number"], p.I35["real number"], allow_id=True))
def test_c09b__is_instance_of(self):
with p.uri_context(uri=TEST_BASE_URI):
i1 = p.instance_of(p.I39["positive integer"])
self.assertTrue(p.is_instance_of(i1, p.I39["positive integer"]))
self.assertTrue(p.is_instance_of(i1, p.I37["integer number"]))
self.assertTrue(p.is_instance_of(i1, p.I34["complex number"]))
i2 = p.instance_of(p.I37["integer number"])
self.assertTrue(p.is_instance_of(i2, p.I37["integer number"]))
self.assertTrue(p.is_instance_of(i2, p.I34["complex number"]))
self.assertFalse(p.is_instance_of(i2, p.I39["positive integer"]))
with self.assertRaises(p.aux.TaxonomicError):
# I39 is not an instance -> error
p.is_instance_of(p.I39["positive integer"], p.I39["positive integer"])
def test_c10__qualifiers(self):
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH3, prefix="ag")
itm1: p.Item = p.ds.get_entity_by_key_str("ag__I2746__Rudolf_Kalman")
stm1, stm2 = itm1.get_relations("ag__R1833__has_employer")[:2]
self.assertEqual(len(stm1.qualifiers), 2)
self.assertEqual(len(stm2.qualifiers), 2)
self.assertEqual(len(stm2.dual_statement.qualifiers), 2)
qf1, qf2 = stm2.qualifiers
qf1.unlink()
self.assertEqual(len(stm2.qualifiers), 1)
self.assertEqual(len(stm2.dual_statement.qualifiers), 1)
def test_c11__equation(self):
mod1 = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
# get item via prefix and key
itm1: p.Item = p.ds.get_entity_by_key_str("ma__I3749__Cayley_Hamilton_theorem")
# get item via key and uri
itm2: p.Item = p.ds.get_entity_by_key_str("I3749__Cayley_Hamilton_theorem", mod_uri=mod1.ma.__URI__)
self.assertEqual(itm1, itm2)
itm1_setting_namespace = itm1._ns_setting
# alternative way to access names (graph based but bulky): itm1.scp__context.get_inv_relations("R20"), ...
Z: p.Item = itm1_setting_namespace["Z"]
r31_list = Z.get_inv_relations("R31__is_in_mathematical_relation_with")
# taking the dual because we got it via the inverse relation
stm: p.Statement = r31_list[0].dual_statement
self.assertEqual(len(r31_list), 1)
# test the expected qualifier
q = stm.qualifiers[0]
self.assertEqual(q.subject, stm) # here it is relevant that we used the dual_relation above
self.assertEqual(q.predicate, p.R34["has proxy item"])
# this is the proxy item
eq = q.object
rhs = eq.R27__has_rhs
self.assertEqual(rhs, Z)
# ensure reproducible results of applied mappings
lhs = eq.R26__has_lhs
P: p.Item = itm1_setting_namespace["P"]
A: p.Item = itm1_setting_namespace["A"]
tmp = P(A)
self.assertEqual(lhs, tmp)
def test_c12__process_key_str(self):
# first, check label consistency in builtin_entities
# note these keys do not to exist
pkey1 = p.process_key_str("I0008234")
self.assertEqual(pkey1.short_key, "I0008234")
self.assertEqual(pkey1.label, None)
pkey2 = p.process_key_str("R00001234__my_label", check=False)
self.assertEqual(pkey2.short_key, "R00001234")
self.assertEqual(pkey2.label, "my_label")
# wrong syntax of key_str (missing "__")
self.assertRaises(p.aux.InvalidGeneralKeyError, p.process_key_str, "R1234XYZ")
pkey3 = p.process_key_str("R2__has_description", check=False)
self.assertEqual(pkey3.short_key, "R2")
self.assertEqual(pkey3.label, "has_description")
# wrong label ("_XYZ")
self.assertRaises(ValueError, p.process_key_str, "R2__has_description_XYZ")
# now, check label consistency in the test data
_ = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, TEST_MOD_NAME)
def test_c12a__process_key_str2(self):
ct = p.irkloader.load_mod_from_path(TEST_DATA_PATH2, prefix="ct")
p.ds.get_entity_by_key_str("ct__R7641__has_approximation") == ct.R7641["has approximation"]
with p.uri_context(uri=TEST_BASE_URI):
e0 = p.create_item(key_str="I0124", R1="some label")
# test prefix notation in keyword attributes
# first: missing prefix -> unknown key
with self.assertRaises(p.aux.ShortKeyNotFoundError):
_ = p.create_item(key_str="I0125", R1="some label", R7641__has_approximation=e0)
# second: use prefix to address the correct relation
e1 = p.create_item(key_str="I0125", R1="some label", ct__R7641__has_approximation=e0)
# third: create a relation which has a short key collision with a relation from the ct module
_ = p.create_relation(key_str="R7641", R1="some test relation")
e2 = p.create_item(
key_str="I0126",
R1="some label",
ct__R7641__has_approximation=e0,
R7641__some_test_relation="foo",
)
# this is the verbose way to address a builtin relation
self.assertEqual(e1.bi__R1.value, "some label")
# this is the (necessary) way to address a relation from an external module
self.assertEqual(e1.ct__R7641[0], e0)
self.assertEqual(e2.ct__R7641[0], e0)
# unittest module is also "extern" (because it is currently not active)
with self.assertRaises(AttributeError):
_ = e2.R7641__some_test_relation
with p.uri_context(uri=TEST_BASE_URI, prefix="ut"):
# address the relation with correct prefix
self.assertEqual(e2.ut__R7641__some_test_relation[0], "foo")
# address the relation without prefix (but with activated unittest module)
self.assertEqual(e2.R7641__some_test_relation[0], "foo")
# activate different module and use attribute without prefix
with p.uri_context(uri=ct.__URI__):
self.assertEqual(e2.R7641__has_approximation[0], e0)
def test_c12b__dummy_items_and_relations(self):
"""
Test that constructions like `I000["any label"]` and `R000__any_other_label` work
"""
self.assertEqual(p.I000["foo"], p.I000["bar"])
self.assertEqual(p.R000["foo"], p.R000["bar"])
with p.uri_context(uri=TEST_BASE_URI):
e1 = p.create_item(
key_str="I0124",
R1="test item",
R000__foo=p.I000["foo"],
R000__bar=p.I000["bar"],
)
@unittest.skipIf(os.environ.get("CI"), "Skipping visualization test on CI to prevent graphviz-dependency")
def test_c13__format_label(self):
with p.uri_context(uri=TEST_BASE_URI):
e1 = p.create_item(key_str="I0123", R1="1234567890")
node = visualization.create_node(e1, url_template="")
node.perform_html_wrapping(use_html=False)
label = node.get_dot_label(render=True)
# note: for the sake of brevity we skip quotes inside of [...] for the node-labels in visualization
self.assertEqual(label, "I0123\\n[1234567890]")
with p.uri_context(uri=TEST_BASE_URI):
e1 = p.create_item(key_str="I0124", R1="1234567890abcdefgh")
node = visualization.create_node(e1, url_template="")
node.perform_html_wrapping(use_html=False)
label = node.get_dot_label(render=True)
self.assertEqual(label, "I0124\\n[1234567890a\\nbcdefgh]")
with p.uri_context(uri=TEST_BASE_URI):