Skip to content

omnipy.data.model

Pydantic-backed Omnipy models and model inspection helpers.

This module defines :class:Model, Omnipy's central typed container for a single validated root value, together with helper predicates for recognizing Omnipy models, plain pydantic models, and related class relationships.

CLASS DESCRIPTION
Model

Typed pydantic-backed container for a single validated value.

ModelMetaclass

Metaclass for :class:Model with relaxed None handling.

FUNCTION DESCRIPTION
is_model_instance

Check whether an object is an Omnipy model instance.

is_model_subclass

Check whether a type is an Omnipy model subclass.

is_non_omnipy_pydantic_model

Check whether an object is a pydantic model outside Omnipy's wrappers.

is_pure_pydantic_model

Check whether an object is a direct pydantic.BaseModel subclass instance.

obj_or_model_content_isinstance

Check a plain object or a model's content against a target type.

parse_none_according_to_model

Convert None values according to a model's nested type rules.

prepare_value_for_validation_if_dataset_or_model

Convert model-like inputs to plain data before validation.

ATTRIBUTE DESCRIPTION
dict_t

undefined_default_factory

TYPE: Callable[[], Any]

dict_t module-attribute

dict_t = dict

undefined_default_factory module-attribute

undefined_default_factory: Callable[[], Any] = lambda: Undefined

Model

Bases: ModelDisplayMixin, DataClassBase[_RootT], pyd.GenericModel, Generic[_RootT]


              flowchart BT
              omnipy.data.model.Model[Model]
              omnipy.data._mixins.display.ModelDisplayMixin[ModelDisplayMixin]
              omnipy.data._mixins.display.BaseDisplayMixin[BaseDisplayMixin]
              omnipy.data._data_class_creator.DataClassBase[DataClassBase]

                              omnipy.data._mixins.display.ModelDisplayMixin --> omnipy.data.model.Model
                                omnipy.data._mixins.display.BaseDisplayMixin --> omnipy.data._mixins.display.ModelDisplayMixin
                

                omnipy.data._data_class_creator.DataClassBase --> omnipy.data.model.Model
                
                omnipy.util.pydantic.GenericModel --> omnipy.data.model.Model
                


              click omnipy.data.model.Model href "" "omnipy.data.model.Model"
              click omnipy.data._mixins.display.ModelDisplayMixin href "" "omnipy.data._mixins.display.ModelDisplayMixin"
              click omnipy.data._mixins.display.BaseDisplayMixin href "" "omnipy.data._mixins.display.BaseDisplayMixin"
              click omnipy.data._data_class_creator.DataClassBase href "" "omnipy.data._data_class_creator.DataClassBase"
            

Typed pydantic-backed container for a single validated value.

Model[T] is Omnipy's central data container. Each concrete specialization wraps one root value of type T, validates incoming data with pydantic, and exposes the parsed value through :attr:content. Models also proxy many operations on the wrapped object so they can often be used like the underlying value while still preserving Omnipy validation, conversion helpers, and interactive snapshot semantics.

Concrete models are created either as type aliases such as Model[list[int]] or by subclassing an already-specialized model class.

CLASS DESCRIPTION
Config

Configure pydantic behavior for Omnipy models.

METHOD DESCRIPTION
__init__

Parse input into the concrete model's root value.

absorb_and_replace

Replace this model's content with data parsed from another model.

browse

Opens the model or dataset in a browser, if possible.

clone_model_cls

Create a subclass clone of this concrete model class.

content_validated_according_to_snapshot

Report whether current content still matches the validated snapshot.

copy

Copy the model while avoiding shared mutable content by default.

deepcopy_context

Delegate nested deepcopy bookkeeping to the shared data-class creator.

default_repr_to_terminal_str

Render the default display panel as terminal text.

dict
do

Apply a placeholder-style callable to this model.

from_data

Parse raw Python data into this existing model instance.

from_json

Parse JSON into this existing model instance.

full

Display the content of the Model or Dataset in full height.

full_type

Return the model's full declared root type including type arguments.

get_orig_model

Return the original declared model type before internal normalization.

has_snapshot

Check whether this model currently has a stored snapshot.

inner_type

Return the inner validated root type for this model class.

is_nested_type

Check whether this model wraps a nested or transformed root type.

json

Preview the data content of the Model or Dataset as JSON.

outer_type

Return the declared outer root type for this model class.

peek

Display a preview of the Model or Dataset content.

set_orig_model

Store the original declared model type on the root field metadata.

snapshot_differs_from_model

Check whether the stored snapshot differs from another model's content.

snapshot_taken_of_same_model

Check whether the stored snapshot was taken from model itself.

to

Convert this model into another model class by reparsing its data.

to_data

Serialize the model into raw Python data.

to_json

Serialize the model to JSON.

to_json_schema

Render the model's JSON schema.

update_forward_refs

Resolve forward references for this model and related model bases.

update_reactive_views
validate

Validate a value while preserving Omnipy iterator overrides.

validate_content

Re-validate the current :attr:content value in place.

ATTRIBUTE DESCRIPTION
config

Return the data configuration shared by the owning data-class family.

TYPE: IsDataConfig

content

Access the parsed root value stored by the model.

TYPE: _RootT

reactive_objects

Return the reactive-object registry attached to this data-class family.

TYPE: IsReactiveObjects | None

snapshot

Return the validated snapshot currently tracked for this model.

TYPE: _RootT

snapshot_holder

Return the snapshot holder coordinating copy-based change tracking.

TYPE: IsSnapshotHolder[HasContent, ContentT]

Source code in src/omnipy/data/model.py
 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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
class Model(  # type: ignore[misc]
        ModelDisplayMixin,
        DataClassBase[_RootT],
        pyd.GenericModel,
        Generic[_RootT],
        metaclass=ModelMetaclass,
):
    """Typed pydantic-backed container for a single validated value.

    ``Model[T]`` is Omnipy's central data container. Each concrete
    specialization wraps one root value of type ``T``, validates incoming data
    with pydantic, and exposes the parsed value through :attr:`content`. Models
    also proxy many operations on the wrapped object so they can often be used
    like the underlying value while still preserving Omnipy validation,
    conversion helpers, and interactive snapshot semantics.

    Concrete models are created either as type aliases such as
    ``Model[list[int]]`` or by subclassing an already-specialized model class.
    """
    @classmethod
    def _get_special_methods_info_dict(cls) -> dict_t[str, MethodInfo]:
        return SPECIAL_METHODS_INFO_DICT

    __root__: _RootT = pyd.Field(default_factory=undefined_default_factory)

    # TODO: Pydantic v2, see if slots=True can be used for Model and Dataset to reduce memory usage

    class Config:
        """Configure pydantic behavior for Omnipy models.

        This nested configuration class enables Omnipy's relaxed runtime model
        behavior, including arbitrary wrapped types, eager validation, and enum
        value serialization.

        Attributes:
            arbitrary_types_allowed: Allows root values that are not native
                pydantic field types.
            validate_all: Validates all fields during model creation.
            smart_union: Enables pydantic's smarter union parsing behavior.
            use_enum_values: Serializes enums by their values.
        """
        arbitrary_types_allowed = True
        validate_all = True
        # validate_assignment = True
        smart_union = True
        # json_loads = orjson.loads
        # json_dumps = orjson_dumps
        use_enum_values = True

    def _get_default_factory(self) -> Callable[[], _RootT]:
        """Build a default factory for the current concrete model.

        The factory prefers reusing a previously computed default value when it
        is safe to do so, but falls back to recomputing the default for models
        whose defaults cannot be copied safely.

        Returns:
            Callable[[], _RootT]: A callable producing default root values for
                this model instance.
        """
        try:
            fixed_default_val = self._get_default_value()
            return lambda: fixed_default_val
        except (ValidationError, TypeError, ValueError):
            return lambda: self._get_default_value()

    @classmethod
    def _get_default_value_from_model(  # noqa: C901
            cls,
            model: type[_RootT] | TypeForm | TypeVar,
    ) -> _RootT:
        """Instantiate a default root value from a type expression.

        The method normalizes Omnipy and typing constructs such as
        ``Annotated``, unions, literals, tuples, callables, and type variables
        into a concrete default value that can seed a model instance.

        Args:
            model: Type expression describing the model's root value.

        Returns:
            _RootT: A best-effort default value compatible with ``model``.

        Raises:
            TypeError: If the type expression cannot be instantiated safely.
        """
        model = get_default_if_typevar(model)
        origin_type = get_origin(model)
        args = get_args(model)

        if origin_type is Annotated:
            model = args[0]
            origin_type = get_origin(model)
            args = get_args(model)

        if origin_type in (None, ()):
            origin_type = model

        if origin_type is None:
            origin_type = NoneType

        if origin_type in [Union, UnionType]:
            if any(is_none_type(arg) for arg in args):
                return cast(_RootT, None)

            last_error_holder = LastErrorHolder()
            for arg in args:
                if callable(arg) or isinstance(arg, TypeVar):
                    with last_error_holder:
                        return cls._get_default_value_from_model(arg)
            last_error_holder.raise_derived(TypeError(f'Cannot instantiate model "{model}".'))

        if origin_type is tuple and args and Ellipsis not in args:
            return cast(_RootT, tuple(cls._get_default_value_from_model(arg) for arg in args))

        if origin_type is Literal:
            return args[0]

        if origin_type is Callable:
            return cast(_RootT, lambda: None)

        if origin_type is ForwardRef or type(origin_type) is ForwardRef:
            raise TypeError(f'Cannot instantiate model "{model}". ')

        return cast(_RootT, origin_type())  # type: ignore[misc]

    @classmethod
    def _prepare_cls_members_to_mimic_model(  # noqa: C901
            cls,
            created_model: 'type[Model[_RootT]]',
    ) -> None:
        """Install special-method proxies matching the wrapped root type.

        Omnipy dynamically equips concrete ``Model[T]`` classes with special
        methods such as arithmetic, iteration, and container operations when
        the wrapped type supports them.

        Args:
            created_model: Concrete model class to augment with proxied special
                methods.

        """
        from omnipy.data._typing.helpers import all_model_type_variants

        outer_types = all_model_type_variants(created_model)

        def _type_supports_method(_type: type | GenericAlias, _method_name: str) -> bool:
            """Check whether a type meaningfully implements a special method.

            Args:
                _type: Candidate runtime type or specialized generic alias.
                _method_name: Special-method name to test.

            Returns:
                bool: ``True`` when ``_type`` should be treated as supporting
                    ``_method_name``.
            """
            if is_literal_type(_type):
                # Literal types should be considered to support the same
                # methods as their underlying type, e.g. int for Literal[3]
                _type = get_args(_type)[0].__class__
            elif get_args(_type):
                # If type is a specialization of a generic type, e.g.
                # MyList[int], we want to check the methods of the
                # underlying generic type, e.g. MyList, as the
                # specialization of non-builtin types typically does not
                # have any special methods.
                _type = cast(type, get_origin(_type))

            method: Callable | None = getattr(_type, _method_name, None)
            if method is None:
                return False

            # We need to check for e.g. object.__or__, which was added
            # in Python 3.10 for e.g 'str | int' and is supported by
            # all types, but should not be considered as a supported
            # method for the model.

            ALWAYS_SUPPORTED_METHODS = ('__delattr__', '__hash__')

            if (_type is object or is_type_specialization(_type)
                    or _method_name in ALWAYS_SUPPORTED_METHODS):
                return True

            # __objclass__ exists for slot_wrappers (built-ins)
            objclass = getattr(method, '__objclass__', None)
            if objclass is not None:
                # Check if the method is defined on the type itself or
                # inherited from a parent class other than object or type
                return objclass not in (type, object)

            return True

        if any(lenient_isinstance(_type, TypeVar) for _type in outer_types):
            return

        for name, method_info in created_model._get_special_methods_info_dict().items():
            method_defined_before_model = False
            for base in created_model.__mro__:
                if base is Model:
                    break
                if name in base.__dict__:
                    if name == '__hash__' and base.__dict__[name] is None:
                        continue
                    method_defined_before_model = True
                    break

            if method_defined_before_model:
                continue

            names_to_check = (name, '__add__') if name in ('__iadd__', '__radd__') else (name,)
            for type_to_support in outer_types:
                if any(_type_supports_method(type_to_support, _) for _ in names_to_check):
                    setattr(created_model,
                            name,
                            functools.partialmethod(cls._special_method, name, method_info))
                    break

    @override
    def __class_getitem__(  # type: ignore[override]
        cls,
        params: type[_RootT] | tuple[type[_RootT]] | TypeVar | tuple[TypeVar],
    ) -> 'type[Model[_RootT]]':
        """Create a concrete ``Model[T]`` specialization.

        Args:
            params: Type expression describing the wrapped root value.

        Returns:
            A concrete :class:`Model` subclass bound to ``params``.
        """

        model = cls._prepare_params(params)

        orig_model: type[_RootT] | TypeVar = model

        # Populating the root field at runtime instead of providing a __root__ Field explicitly
        # is needed due to the inability of typing/pydantic to provide a dynamic default based on
        # the actual type. The following issue in mypy seems relevant:
        # https://github.com/python/mypy/issues/3737 (as well as linked issues)

        created_model = cast(
            type[Model],
            super().__class_getitem__(model if cls is Model else params),  # type: ignore
        )

        created_model._get_root_field().field_info = deepcopy(
            created_model._get_root_field().field_info)

        if cls is Model and orig_model is not _RootT:  # type: ignore[misc]
            created_model._get_root_field().field_info.extra = {'orig_model': orig_model}

        created_model._inherit_first_orig_model_in_bases_if_missing()

        cls._recursively_set_allow_none(created_model._get_root_field())

        # As long as models are not created concurrently, setting the class members temporarily
        # should not have averse effects
        # TODO: Check if we can move to explicit definition of __root__ field at the object
        #       level in pydantic 2.0 (when it is released)

        if created_model is not cls:
            cleanup_name_qualname_and_module(cls, created_model, orig_model)

        cls._prepare_cls_members_to_mimic_model(created_model)

        return created_model

    @classmethod
    def _inherit_first_orig_model_in_bases_if_missing(cls):
        """Copy original model metadata from concrete model bases when absent.

        This keeps derived model classes aligned with the earliest recorded
        original type expression even after pydantic-generated intermediate base
        classes are involved.

        Returns:
            None: This method updates class metadata and clears type caches.
        """
        if cls is not Model:
            for orig_base in get_original_bases(cls):
                if isinstance(orig_base, ModelMetaclass):
                    model_base = cast(type[Model], orig_base)
                    if model_base.__concrete__:
                        model_base._inherit_first_orig_model_in_bases_if_missing()
                        orig_model = model_base.get_orig_model()
                        if orig_model is not Undefined:
                            cls.set_orig_model(orig_model)
                            break

            cls._clean_type_caches()

    if TYPE_CHECKING and TYPE_CHECKER != 'mypy':  # noqa: C901

        # mypy currently does not support overloads of __new__()

        from omnipy.data._typing.mimic_models import (Model_bool,
                                                      Model_bytes,
                                                      Model_Dataset,
                                                      Model_dict,
                                                      Model_float,
                                                      Model_int,
                                                      Model_list,
                                                      Model_set,
                                                      Model_str,
                                                      Model_tuple_pair,
                                                      Model_tuple_same_type)

        @overload
        def __new__(
            cls: 'type[Model[float]]' | 'type[Model[Model[float]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_float:
            """Type-check construction of float-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_float: A statically narrowed float model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[int]]' | 'type[Model[Model[int]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_int:
            """Type-check construction of int-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_int: A statically narrowed int model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[bool]]' | 'type[Model[Model[bool]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_bool:
            """Type-check construction of bool-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_bool: A statically narrowed bool model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[str]]' | 'type[Model[Model[str]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_str:
            """Type-check construction of string-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_str: A statically narrowed string model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[bytes]]' | 'type[Model[Model[bytes]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_bytes:
            """Type-check construction of bytes-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_bytes: A statically narrowed bytes model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[set[_ValT]]]| type[Model[Model[set[_ValT]]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_set[_ValT]:
            """Type-check construction of set-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_set[_ValT]: A statically narrowed set model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[list[_ValT]]]| type[Model[Model[list[_ValT]]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_list[_ValT]:
            """Type-check construction of list-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_list[_ValT]: A statically narrowed list model instance.
            """
            ...

        @overload
        def __new__(  # pyright: ignore[reportOverlappingOverload]
            cls: 'type[Model[tuple[_ValT, _ValT2]]] | type[Model[Model[tuple[_ValT, _ValT2]]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_tuple_pair[_ValT, _ValT2]:
            """Type-check construction of fixed two-item tuple models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_tuple_pair[_ValT, _ValT2]: A statically narrowed tuple
                    pair model instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[tuple[_ValT, ...]]] | type[Model[Model[tuple[_ValT, ...]]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_tuple_same_type[_ValT]:
            """Type-check construction of homogeneous tuple models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_tuple_same_type[_ValT]: A statically narrowed tuple model
                    instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[dict_t[_KeyT, _ValT]]] | type[Model[Model[dict_t[_KeyT, _ValT]]]]',
            *args: Any,
            **kwargs: Any,
        ) -> Model_dict[_KeyT, _ValT]:
            """Type-check construction of dict-based models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_dict[_KeyT, _ValT]: A statically narrowed dict model
                    instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[Dataset[_OtherModelT]]]',
            *args: Any,
            **kwargs: Any,
        ) -> 'Model_Dataset[_OtherModelT]':
            """Type-check construction of dataset-backed models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_Dataset[_OtherModelT]: A statically narrowed dataset model
                    instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[Model[Dataset[_DatasetT | _OtherModelT]]]',
            *args: Any,
            **kwargs: Any,
        ) -> 'Model_Dataset[_DatasetT]':
            """Type-check construction of dataset union models.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model_Dataset[_DatasetT]: A statically narrowed dataset model
                    instance.
            """
            ...

        @overload
        def __new__(
            cls: 'type[_ModelT]',
            *args: Any,
            **kwargs: Any,
        ) -> '_ModelT':
            """Type-check construction of arbitrary concrete model subclasses.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                _ModelT: A statically narrowed instance of ``cls``.
            """
            ...

        def __new__(
            cls,
            *args: Any,
            **kwargs: Any,
        ) -> 'Model | _ModelT':
            """Type-check construction of runtime model instances.

            Args:
                *args: Positional arguments forwarded to runtime construction.
                **kwargs: Keyword arguments forwarded to runtime construction.

            Returns:
                Model | _ModelT: A model instance matching the active overload.
            """
            ...
    else:

        def __new__(  # type: ignore[no-redef]
                cls,
                *args: Any,
                **kwargs: Any,
        ) -> Self:
            """Create an instance only for concrete ``Model[T]`` specializations.

            Args:
                *args: Positional arguments forwarded to instance creation.
                **kwargs: Keyword arguments forwarded to instance creation.

            Returns:
                A new instance of the concrete model class.

            Raises:
                TypeError: If ``Model`` is instantiated without first binding a
                    concrete root type.
            """
            model_not_specified = ROOT_KEY not in cls.__fields__
            if model_not_specified:
                cls._raise_no_model_exception()

            return super().__new__(cls)

    @classmethod
    def get_orig_model(cls) -> type[_RootT] | UndefinedType:
        """Return the original declared model type before internal normalization.

        Returns:
            The original type expression supplied for this model specialization,
            or :data:`Undefined` when no original type has been recorded.
        """
        if cls.__fields__[ROOT_KEY].field_info and cls.__fields__[ROOT_KEY].field_info.extra:
            return cls.__fields__[ROOT_KEY].field_info.extra.get('orig_model', Undefined)
        return Undefined

    @classmethod
    def set_orig_model(cls, orig_model: TypeForm) -> None:
        """Store the original declared model type on the root field metadata.

        Args:
            orig_model: Original type expression to associate with the model.
        """
        cls.__fields__[ROOT_KEY].field_info.extra['orig_model'] = orig_model

    def __init__(  # noqa: C901
        self,
        value: _RootT | object | UndefinedType = Undefined,
        *,
        __root__: _RootT | object | UndefinedType = Undefined,
        **kwargs: _RootT | object,
    ) -> None:
        """Parse input into the concrete model's root value.

        The constructor accepts either a direct root value, the pydantic-style
        ``__root__`` keyword, or keyword pairs for dict-like models. Omnipy also
        accepts datasets, other models, and plain pydantic models as input and
        converts them to raw data before validation.

        Args:
            value: Root value to parse.
            __root__: Alternative explicit root value.
            **kwargs: Mapping-style root content for dict-like models.

        Raises:
            AssertionError: If root data is supplied through more than one input
                path.
            ValidationError: If the provided data cannot be parsed as this
                model's declared type.
        """
        super_kwargs: dict[str, _RootT] = {}
        num_root_vals = 0

        if value is not Undefined:
            super_kwargs[ROOT_KEY] = cast(_RootT, value)
            num_root_vals += 1

        if __root__ is not Undefined:
            super_kwargs[ROOT_KEY] = cast(_RootT, __root__)
            num_root_vals += 1

        if kwargs:
            super_kwargs[ROOT_KEY] = cast(_RootT, kwargs)
            kwargs = {}
            num_root_vals += 1

        assert num_root_vals <= 1, 'Not allowed to provide root data in more than one argument'

        if self._get_root_field().default_factory is undefined_default_factory:
            self._get_root_field().default_factory = self._get_default_factory()

        dataset_or_model_as_input = False
        if ROOT_KEY in super_kwargs:
            try:
                dataset_or_model_as_input, value = \
                    prepare_value_for_validation_if_dataset_or_model(super_kwargs[ROOT_KEY])
            except Exception as exc:
                val_exc = ValueError(f'Failed to prepare value for validation: {exc}')
                raise ValidationError(
                    [pyd.ErrorWrapper(exc, loc=ROOT_KEY), pyd.ErrorWrapper(val_exc, loc=ROOT_KEY)],
                    self.__class__)
            if dataset_or_model_as_input:
                super_kwargs[ROOT_KEY] = cast(_RootT, value)

        self._init(super_kwargs, **kwargs)

        try:
            self._primary_validation(super_kwargs)
        except ValidationError:
            if dataset_or_model_as_input:
                self._secondary_validation_from_data(super_kwargs)
            else:
                raise

        if not self.__class__.__doc__:
            self._set_standard_field_description()

    def _get_default_value(self) -> _RootT:
        """Compute the default root value for this concrete model instance.

        Returns:
            _RootT: Default value derived from the model's full root type.
        """
        return self.__class__._get_default_value_from_model(self.full_type())

    def _primary_validation(self, super_kwargs):
        """Run the primary pydantic validation pass.

        Args:
            super_kwargs: Root-field payload forwarded to ``GenericModel``.

        Returns:
            None: The validated state is stored on ``self``.

        Raises:
            ValidationError: If pydantic rejects the provided root payload.
        """
        # Pydantic validation of super_kwargs
        validate_cls_counts[self.__class__.__name__] += 1
        super().__init__(**super_kwargs)

    def _secondary_validation_from_data(self, super_kwargs):
        """Retry validation by reparsing prepared raw data.

        Args:
            super_kwargs: Root-field payload whose ``__root__`` entry should be
                reparsed through :meth:`from_data`.

        Returns:
            None: The reparsed value is stored on ``self``.

        Raises:
            ValidationError: If reparsing still fails.
        """
        super().__init__()
        self.from_data(super_kwargs[ROOT_KEY])

    def _init(self, super_kwargs: dict_t[str, Any], **kwargs: Any) -> None:
        ...

    def __del__(self):
        """Schedule snapshot cleanup when the model instance is garbage-collected.

        """
        content_id = id(self.content)
        self.snapshot_holder.schedule_deepcopy_content_ids_for_deletion(content_id)

    def __copy__(self) -> Self:
        """Return a shallow copy using Omnipy's custom copy semantics.

        Returns:
            A shallow-copied model instance whose mutable content is not shared
            with the original.
        """
        return self.copy(deep=False)

    if TYPE_CHECKING:

        @override
        def __iter__(self) -> Iterator:  # type: ignore[override]
            """Type-check iteration over wrapped iterable content.

            Returns:
                Iterator: Iterator over the wrapped content.
            """
            ...

    def copy(self, *, deep: bool = False, **kwargs) -> Self:
        """Copy the model while avoiding shared mutable content by default.

        Omnipy overrides pydantic's copy semantics so a shallow copy still gets
        a shallow-copied root value instead of sharing the same mutable object.

        Args:
            deep: When ``True``, perform a deep copy.
            **kwargs: Additional keyword arguments forwarded to pydantic's
                ``copy()`` implementation.

        Returns:
            A copied model instance.
        """
        pydantic_copy = pyd.GenericModel.copy(self, deep=deep, **kwargs)
        if not deep:
            # Shallow copying of the model should not share the same
            # content, as this can lead to unintentional side effects when
            # the content is mutable.
            pydantic_copy.content = copy(pydantic_copy.__dict__[ROOT_KEY])
        return pydantic_copy  # pyright: ignore[reportReturnType]

    @classmethod
    def clone_model_cls(cls, new_model_cls_name: str) -> type[Self]:
        """Create a subclass clone of this concrete model class.

        Args:
            new_model_cls_name: Name to assign to the cloned class.

        Returns:
            A new subclass with the same behavior and type binding.
        """
        new_model_cls = type(new_model_cls_name, (cls,), {})
        return cast(type[Self], new_model_cls)

    @staticmethod
    def _raise_no_model_exception() -> None:
        """Raise the standard error for unspecialized ``Model`` construction.

        Raises:
            TypeError: Always raised to explain how to bind a concrete model
                type before instantiation.
        """
        raise TypeError('Note: The Model class requires a concrete model to be specified as '
                        'a type hierarchy within brackets either directly, e.g.:\n\n'
                        '\tmodel = Model[list[int]]([1,2,3])\n\n'
                        'or indirectly in a subclass definition, e.g.:\n\n'
                        '\tclass MyNumberList(Model[list[int]]): ...\n\n')

    def _set_standard_field_description(self) -> None:
        """Populate the root field description when the class lacks a docstring.
        """
        self.__fields__[ROOT_KEY].field_info.description = self._get_standard_field_description()

    @classmethod
    def _get_standard_field_description(cls) -> str:
        """Return the fallback root-field description for generated models.

        Returns:
            str: Standard descriptive text for the root field metadata.
        """
        return ('This class represents a concrete model for data items in the `omnipy` Python '
                'package. It is a statically typed specialization of the Model class, '
                'which is itself wrapping the excellent Python package named `pydantic`.')

    @classmethod
    def validate(cls: type['Model'], value: Any) -> 'Model':
        """Validate a value while preserving Omnipy iterator overrides.

        This method is primarily an internal compatibility shim for pydantic's
        validation API. Omnipy temporarily restores pydantic's original
        ``__iter__`` behavior when validating model instances so custom iterator
        proxying does not interfere with validation.

        Args:
            value: Value to validate as an instance of ``cls``.

        Returns:
            A validated model instance.
        """
        # TODO: Doublecheck if validate() method is still needed for pydantic v2

        validate_cls_counts[cls.__name__] += 1
        if is_model_instance(value):

            @contextmanager
            def temporary_set_value_iter_to_pydantic_method() -> Iterator[None]:
                """Temporarily restore pydantic's iterator implementation.

                Returns:
                    Iterator[None]: Context manager generator that swaps in the
                        original pydantic ``__iter__`` implementation during
                        validation.
                """
                prev_iter = value.__class__.__iter__
                value.__class__.__iter__ = pyd.GenericModel.__iter__  # type: ignore[method-assign]

                try:
                    yield
                finally:
                    value.__class__.__iter__ = prev_iter  # type: ignore[method-assign]

            with temporary_set_value_iter_to_pydantic_method():
                return super().validate(value)
        else:
            return super().validate(value)

    @classmethod
    def update_forward_refs(
        cls,
        calling_module: str | None = None,
        prev_visited_classes: set[type] | None = None,
        **localns: Any,
    ) -> None:
        """Resolve forward references for this model and related model bases.

        Omnipy extends pydantic's behavior by merging namespaces from both the
        defining module and the calling module, then propagating the same context
        through parent model classes. This keeps forward references working when
        specialized models are defined in one module and used from another.

        Args:
            calling_module: Module name to use as the caller context. When not
                provided, Omnipy infers it from the call stack.
            prev_visited_classes: Set used internally to avoid revisiting model
                classes during recursive propagation.
            **localns: Additional local names available while resolving forward
                references.
        """
        if prev_visited_classes is None:
            prev_visited_classes = set()
        elif cls in prev_visited_classes:
            return

        # Merge the namespaces of the Model's own module and the calling
        # module to the local namespace for evaluation of forward
        # references, which is necessary for cases where the Model is
        # defined in a different module than where it is used, e.g. when
        # the Model is defined in a library and used by a user in their
        # own code.
        if calling_module is None:
            calling_module = get_calling_module_name()
        own_module_ns, globalns = \
            build_own_module_and_global_namespace_for_forward_refs(cls, calling_module, **localns)

        prev_outer_type = cls._get_root_field().outer_type_
        prev_type = cls._get_root_field().type_

        super().update_forward_refs(**globalns)

        cls._get_root_field().outer_type_ = evaluate_any_forward_refs_if_possible(
            prev_outer_type, **globalns)
        cls._get_root_field().type_ = evaluate_any_forward_refs_if_possible(prev_type, **globalns)
        cls.set_orig_model(evaluate_any_forward_refs_if_possible(cls.get_orig_model(), **globalns))
        if ROOT_KEY in cls.__annotations__:
            cls.__annotations__[ROOT_KEY] = evaluate_any_forward_refs_if_possible(
                cls.__annotations__[ROOT_KEY], **globalns)

        cls._clean_type_caches()

        cls._recursively_set_allow_none(cls._get_root_field())

        cls._prepare_cls_members_to_mimic_model(cls)

        prev_visited_classes.add(cls)

        # Propagate update_forward_refs to parent models but retaining the
        # same calling module. This is needed to ensure the correct
        # context is used to resolve forward references in complex
        # inheritance hierarchies.
        #
        # We explicitly call `update_forward_refs` on immediate parent
        # classes (`__bases__`) instead of relying solely on
        # `super().update_forward_refs()`. This is because `super()`
        # inside this classmethod resolves relative to `Model` in the MRO,
        # silently bypassing custom logic on any intermediate `Model`
        # subclasses. Explicitly propagating through `__bases__` ensures
        # that class-level setups are correctly applied to all parents
        # exactly once, efficiently preventing redundant updates.
        for base in cls.__bases__:
            if is_model_subclass(base) and base is not Model:
                # Merge the current class's own module namespace into
                # localns before propagating, so that pydantic-generated
                # parametrized base classes (which have
                # __module__='omnipy.data.model' rather than the defining
                # module) can still resolve forward refs that only exist
                # in the defining module's namespace.

                extra_ns: dict[str, Any] = {}
                extra_ns.update(**own_module_ns)
                extra_ns.update(**localns)

                base.update_forward_refs(
                    calling_module=calling_module,
                    prev_visited_classes=prev_visited_classes,
                    **extra_ns,
                )

        cls.__name__ = remove_forward_ref_notation(cls.__name__)
        cls.__qualname__ = remove_forward_ref_notation(cls.__qualname__)

    def validate_content(self) -> None:
        """Re-validate the current :attr:`content` value in place.

        Raises:
            ValidationError: If the current content no longer satisfies the
                model's declared type.
        """
        self._validate_and_set_value(self.content)

    def _validate_and_set_value(
        self,
        new_content: object,
        reset_solution: ContextManager[None] | None = None,
        lazy_snapshot_if_possible: bool = False,
    ) -> None:
        """Validate a candidate root value and store it on the model.

        Args:
            new_content: Candidate content to validate.
            reset_solution: Optional context manager used to restore state on
                validation failure.
            lazy_snapshot_if_possible: When ``True``, delay snapshot refresh when
                safe to do so.

        Raises:
            ValidationError: If ``new_content`` does not satisfy the model type.
        """

        old_content_id = id(self.content)

        def _set_new_content(content: object) -> None:
            """Replace stored content only when object identity changes.

            Args:
                content: Validated content object to store.

            """
            if id(content) != old_content_id:
                self.content = content  # type: ignore[assignment]

        self._generic_validate_content(
            new_content=new_content,
            outer_reset_solution=reset_solution,
            post_validation_func=_set_new_content,
            lazy_snapshot_if_possible=lazy_snapshot_if_possible,
        )

    def _prepare_reset_solution_take_snapshot_if_needed(
        self,
        /,
    ) -> ResetSolutionTuple:
        """Prepare rollback handling and eager snapshotting for validation.

        Returns:
            ResetSolutionTuple: Reset context plus a flag describing whether a
                snapshot was taken during preparation.
        """
        snapshot_taken = False
        if self.config.model.interactive:
            # TODO: Lazy snapshotting causes unneeded double validation for data that is later
            #       validated for snapshot. Perhaps add a dirty flag to snapshot that can be used
            #       to determine if re-validation is needed? This can also help avoid equality
            #       tests, which might be expensive for large data structures.
            needs_pre_validation = (not self.has_snapshot()
                                    or not self.content_validated_according_to_snapshot())
            if needs_pre_validation:
                internal_reset_solution = self._get_reset_solution()
                with internal_reset_solution:
                    self._validate_and_set_value(
                        self.content, reset_solution=internal_reset_solution)
                    snapshot_taken = True

        return ResetSolutionTuple(
            reset_solution=self._get_reset_solution(),
            snapshot_taken=snapshot_taken,
        )

    def _get_reset_solution(self) -> ContextManager[None]:
        """Return the active rollback strategy for state-changing operations.

        Returns:
            ContextManager[None]: Snapshot-based rollback context in interactive
                mode, otherwise a no-op context manager.
        """
        if self.config.model.interactive and self.has_snapshot():
            return self._get_revert_to_snapshot_reset_solution()
        else:
            return nothing()

    def _get_revert_to_snapshot_reset_solution(self) -> ContextManager[None]:
        """Create a reset context that restores the current snapshot on failure.

        Returns:
            ContextManager[None]: Context manager that restores snapshot state if
                an exception escapes the protected block.
        """
        prev_deepcopy_content_ids = SetDeque[int]()

        def _setup():
            """Capture existing tracked deepcopy identifiers before mutation.

            Returns:
                None: Previous identifiers are recorded in the closure.
            """
            prev_deepcopy_content_ids.extend(self.snapshot_holder.get_deepcopy_content_ids())

        def _handle_exception():
            """Restore snapshot state and merge deferred cleanup identifiers.

            Returns:
                None: Snapshot rollback is applied in place.
            """
            new_deepcopy_content_ids = SetDeque[int](
                self.snapshot_holder.get_deepcopy_content_ids())
            new_deepcopy_content_ids.extend(prev_deepcopy_content_ids)
            self.snapshot_holder.schedule_deepcopy_content_ids_for_deletion(
                *new_deepcopy_content_ids)
            # self.content = self.snapshot_holder.get_snapshot_deepcopy(self)
            self.content = deepcopy(self.snapshot)

        return setup_and_teardown_callback_context(
            setup_func=_setup,
            exception_func=_handle_exception,
        )

    def _generic_validate_content(
        self,
        /,
        new_content: object,
        outer_reset_solution: ContextManager[None] | None = None,
        post_validation_func: Callable[[_RootT], None] | None = None,
        lazy_snapshot_if_possible: bool = False,
    ) -> None:
        """Validate content with optional rollback and post-processing hooks.

        Args:
            new_content: Candidate value to validate.
            outer_reset_solution: Existing rollback context supplied by the
                caller.
            post_validation_func: Optional callback run with the validated
                content before snapshot handling.
            lazy_snapshot_if_possible: When ``True``, avoid unnecessary snapshot
                refreshes when safe.

            ValidationError: If ``new_content`` fails validation.
        """
        keep_alive_old_content = self.content  # To ensure old content ids are not reused

        inner_reset_solution: ContextManager[None]
        if outer_reset_solution:
            inner_reset_solution = nothing()
        else:
            validating_self = new_content is self.content
            reset_solution_tuple = self._prepare_reset_solution_take_snapshot_if_needed()
            if validating_self and reset_solution_tuple.snapshot_taken:
                return
            inner_reset_solution = reset_solution_tuple.reset_solution

        with (inner_reset_solution):
            validated_content = self._validate_content_from_value(new_content)

            if validated_content is new_content:
                validated_content = copy(validated_content)

            if post_validation_func:
                post_validation_func(validated_content)
        del inner_reset_solution

        del new_content
        if self.has_snapshot() or not lazy_snapshot_if_possible:
            self._take_snapshot_of_validated_content()

        del keep_alive_old_content

    def _validate_content_from_value(
        self,
        value: object,
    ) -> _RootT:
        _, value = prepare_value_for_validation_if_dataset_or_model(value)

        values, _, validation_error = pyd.validate_model(self.__class__, {ROOT_KEY: value})
        if validation_error:
            raise validation_error

        return values[ROOT_KEY]

    @property
    def snapshot(self) -> _RootT:
        """Return the validated snapshot currently tracked for this model.

        Returns:
            The snapshot value stored for the current model instance.

        Raises:
            AssertionError: If no snapshot has been taken yet.
        """
        snapshot_wrapper = self._get_snapshot_wrapper()
        assert snapshot_wrapper.id == id(self)
        return snapshot_wrapper.snapshot

    def has_snapshot(self) -> bool:
        """Check whether this model currently has a stored snapshot.

        Returns:
            ``True`` if interactive snapshot state exists for this model.
        """
        return self in self.snapshot_holder

    def _get_snapshot_wrapper(self) -> IsSnapshotWrapper[IsModel, _RootT]:
        """Return the snapshot wrapper currently registered for this model.

        Returns:
            IsSnapshotWrapper[IsModel, _RootT]: Snapshot metadata and payload for
                this model.

        Raises:
            AssertionError: If no snapshot has been taken yet.
        """
        assert self.has_snapshot(), 'No snapshot taken yet'
        return self.snapshot_holder[self]

    def snapshot_taken_of_same_model(self, model: 'Model') -> bool:
        """Check whether the stored snapshot was taken from ``model`` itself.

        Args:
            model: Model instance to compare against the snapshot origin.

        Returns:
            ``True`` if the snapshot was recorded from the same object identity.
        """
        snapshot_wrapper = self._get_snapshot_wrapper()
        return snapshot_wrapper.taken_of_same_obj(model)

    def snapshot_differs_from_model(self, model: 'Model') -> bool:
        """Check whether the stored snapshot differs from another model's content.

        Args:
            model: Model whose current content should be compared with the
                snapshot.

        Returns:
            ``True`` if the snapshot content differs from ``model.content``.
        """
        snapshot_wrapper = self._get_snapshot_wrapper()
        return snapshot_wrapper.differs_from(model.content)

    def content_validated_according_to_snapshot(self) -> bool:
        """Report whether current content still matches the validated snapshot.

        Returns:
            ``True`` when the current content is still represented by the stored
            snapshot and does not need re-validation.
        """
        needs_validation = self.snapshot_differs_from_model(self) \
            or not self.snapshot_taken_of_same_model(self)
        return not needs_validation

    def _take_snapshot_of_validated_content(self) -> None:
        """Store a validated snapshot when interactive mode is enabled.
        """
        if self.config.model.interactive:
            with self.deepcopy_context(self.snapshot_holder.take_snapshot_setup,
                                       self.snapshot_holder.take_snapshot_teardown):
                self.snapshot_holder.take_snapshot(self)

    @classmethod
    def _parse_data(cls, data: Any) -> _RootT:
        """Hook for subclasses to preprocess raw root data before validation.

        Args:
            data: Raw input value prepared by root validators.

        Returns:
            _RootT: Unchanged ``data`` in the base implementation.
        """
        return data

    # TODO: See if it is possible to support general mappings similarly to iterables (in Model)
    #       (note: this is an old TODO, it is unclear what exactly is not supported...)
    @pyd.root_validator(pre=True)
    def _generous_iterable_support(cls, root_obj: dict_t[str, _RootT | None]) -> Any:
        if ROOT_KEY in root_obj:
            value = root_obj[ROOT_KEY]
            outer_type = cls.outer_type()
            if (lenient_issubclass(outer_type, Iterable)
                    and not lenient_isinstance(value, outer_type)  # type: ignore[arg-type]
                    and is_non_str_byte_iterable(value)
                    # Leave the types below for pydantic to handle
                    and not pyd.sequence_like(value)
                    # Also, exclude mappings
                    and not isinstance(value, Mapping)):
                return {ROOT_KEY: (_ for _ in value)}
        return root_obj

    @pyd.root_validator
    def _parse_root_object(cls, root_obj: dict_t[str, _RootT | None]) -> Any:
        assert ROOT_KEY in root_obj
        value = root_obj[ROOT_KEY]
        value = parse_none_according_to_model(value, root_model=cls)

        config = cls.data_class_creator.config  # type: ignore[attr-defined]
        with hold_and_reset_prev_attrib_value(config.model,
                                              'dynamically_convert_elements_to_models'):
            config.model.dynamically_convert_elements_to_models = False
            return {ROOT_KEY: cls._parse_data(value)}

    # TODO: Rename Model.content to Model.content as it may be a single value, while "content"
    #       implies a countable collection of values
    @property
    def content(self) -> _RootT:
        """Access the parsed root value stored by the model.

        Returns:
            The current validated root value.
        """
        return cast(_RootT, self.__dict__.get(ROOT_KEY))

    @content.setter
    def content(self, value: _RootT) -> None:
        """Set the root value without triggering automatic validation.

        Args:
            value: New root value to assign directly.

        Note:
            Unlike :meth:`__init__`, :meth:`from_data`, and :meth:`from_json`,
            direct assignment does not validate the value automatically. Call
            :meth:`validate_content` when you need the assignment checked.
        """
        super().__setattr__(ROOT_KEY, value)

    def to(self, model_cls: type[_OtherModelT]) -> _OtherModelT:
        """Convert this model into another model class by reparsing its data.

        Args:
            model_cls: Destination model class.

        Returns:
            A new instance of ``model_cls`` initialized from this model.
        """
        return model_cls(self)

    def do(self, placeholder: F) -> Any:
        """Apply a placeholder-style callable to this model.

        Args:
            placeholder: Callable placeholder from Omnipy's ``F`` helper.

        Returns:
            Whatever value ``placeholder`` returns for this model instance.
        """
        return placeholder(self)

    def dict(self, *args, **kwargs) -> dict_t[str, object]:
        return {ROOT_KEY: self.to_data()}

    # TODO: Improve typing of to_data/from_data. Should be limited to JSON types at least, but also
    #       `_RootT` for simple models (without submodels). Handling Submodels is tricky, and may
    #       not be possible, e.g. `Model[list[Model[int]]().to_data()` should be type `list[int]`.
    #       A possibility is to support manually providing proper to_data, e.g. through
    #       Generic Mixin class, e.g.:
    #       ```python
    #       class MyModel(Model[list[Model[int]]], ModelData[list[int]]):
    #          ...
    #       ```
    def to_data(self) -> object:
        """Serialize the model into raw Python data.

        Returns:
            The wrapped value converted to plain data, including recursive
            conversion of nested Omnipy models.
        """
        return super().dict(by_alias=True)[ROOT_KEY]

    def _empty_from_data(self, value: object) -> None:
        """Load data into an empty model using a temporary default reset hook.

        Args:
            value: Raw data to parse into the current model.
        """
        @contextmanager
        def _reset_to_default(*args, **kwds):
            """Temporarily restore the model's default content on rollback.

            Args:
                *args: Unused positional arguments required by the contextmanager
                    protocol.
                **kwds: Unused keyword arguments required by the contextmanager
                    protocol.

            Returns:
                Generator[None, None, None]: Context manager generator that
                    resets content before yielding.
            """
            self.content = self._get_default_value_from_model(self.full_type())
            yield

        self._validate_and_set_value(
            value, reset_solution=_reset_to_default(), lazy_snapshot_if_possible=True)

    def from_data(self, data: Any) -> None:
        """Parse raw Python data into this existing model instance.

        Args:
            data: Raw data to validate and store as the model's content.

        Raises:
            ValidationError: If ``data`` cannot be parsed as this model's type.
        """
        if self.content == self._get_default_value_from_model(self.full_type()):
            self._empty_from_data(data)
        else:
            self._validate_and_set_value(data)

    def absorb_and_replace(self, other: 'Model'):
        """Replace this model's content with data parsed from another model.

        Args:
            other: Source model whose serialized data should be absorbed.
        """
        self.from_data(other.to_data())

    def to_json(self, pretty=True) -> str:
        """Serialize the model to JSON.

        Args:
            pretty: When ``True``, return indented human-readable JSON.

        Returns:
            JSON representation of the model content.
        """
        json_content = pyd.BaseModel.json(self)
        if pretty:
            return self._pretty_print_json(json.loads(json_content))
        else:
            return json_content

    def from_json(self, json_content: str) -> None:
        """Parse JSON into this existing model instance.

        Args:
            json_content: JSON document to parse.

        Raises:
            ValidationError: If the JSON content does not match the model type.
        """
        new_model = self.parse_raw(json_content, proto=pyd.Protocol.json)
        self.content = new_model.content

    @classmethod
    @functools.cache
    def inner_type(cls, with_args: bool = False) -> TypeForm:
        """Return the inner validated root type for this model class.

        Args:
            with_args: When ``True``, preserve type arguments such as ``list[int]``.

        Returns:
            The inner root type used after pydantic normalization.
        """
        return cls._get_root_type(outer=False, with_args=with_args)

    @classmethod
    @functools.cache
    def outer_type(cls, with_args: bool = False) -> TypeForm:
        """Return the declared outer root type for this model class.

        Args:
            with_args: When ``True``, preserve type arguments such as ``list[int]``.

        Returns:
            The outer root type exposed by the model.
        """
        return cls._get_root_type(outer=True, with_args=with_args)

    @classmethod
    @functools.cache
    def full_type(cls) -> type[_RootT]:
        """Return the model's full declared root type including type arguments.

        Returns:
            The complete concrete type bound to this model.
        """
        return cast(type[_RootT], cls.outer_type(with_args=True))

    @classmethod
    @functools.cache
    def is_nested_type(cls) -> bool:
        """Check whether this model wraps a nested or transformed root type.

        Returns:
            ``True`` when the inner validated type differs from the declared
            outer type.
        """
        return not cls.inner_type(with_args=True) == cls.outer_type(with_args=True)

    @classmethod
    def _clean_type_caches(cls):
        """Clear cached type-introspection results for this model class.

        Returns:
            None: Cached helper methods are invalidated in place.
        """
        cls._get_root_type.cache_clear()
        cls.outer_type.cache_clear()
        cls.inner_type.cache_clear()
        cls.full_type.cache_clear()
        cls.is_nested_type.cache_clear()

    @classmethod
    def _get_root_field(cls) -> pyd.ModelField:
        """Return pydantic's root field object for the concrete model class.

        Returns:
            pyd.ModelField: Field metadata for ``__root__``.
        """
        return cast(pyd.ModelField, cls.__fields__.get(ROOT_KEY))

    @classmethod
    @functools.cache
    def _get_root_type(cls, outer: bool, with_args: bool) -> TypeForm:
        """Resolve the inner or outer root type for this concrete model class.

        Args:
            outer: When ``True``, return the declared outer type.
            with_args: When ``True``, preserve generic arguments.

        Returns:
            TypeForm: Resolved root type for the requested view.
        """
        root_field = cls._get_root_field()
        root_type = root_field.outer_type_ if outer else root_field.type_

        orig_model = cls.get_orig_model()
        if orig_model != Undefined:
            if not is_optional(root_type) and is_optional(orig_model):
                if outer:
                    root_type = Optional[root_type]
                else:
                    root_type = Optional[root_field.outer_type_]

        return root_type if with_args else ensure_plain_type(root_type)

    # @classmethod
    # def create_from_json(cls, data: str | tuple[str]):
    #     if isinstance(data, tuple):
    #         data = data[0]
    #
    #     obj = cls()
    #     obj.from_json(data)
    #     return obj
    #
    # def __reduce__(self):
    #     return self.__class__.create_from_json, (self.to_json(),)

    @classmethod
    def to_json_schema(cls, pretty=True) -> str:
        """Render the model's JSON schema.

        Args:
            pretty: When ``True``, return indented human-readable JSON.

        Returns:
            JSON schema for the model with Omnipy's ``orig_model`` metadata
            removed.
        """
        schema = cls.schema()
        if 'orig_model' in schema:
            del schema['orig_model']

        if pretty:
            return cls._pretty_print_json(schema)
        else:
            return json.dumps(schema)

    @staticmethod
    def _pretty_print_json(json_content: Any) -> str:
        """Serialize an object as indented JSON text.

        Args:
            json_content: JSON-compatible object to render.

        Returns:
            str: Pretty-printed JSON string.

        Example:
            >>> Model._pretty_print_json({'a': 1})
            '{\n  "a": 1\n}'
        """
        return json.dumps(json_content, indent=2)

    def _check_for_root_key(self) -> None:
        """Ensure the internal root attribute exists on the model instance.

        Raises:
            TypeError: If the model was created without a concrete root binding.
        """
        if ROOT_KEY not in self.__dict__:
            raise TypeError('The Model class requires the specific model to be specified in as '
                            'a type hierarchy within brackets either directly, e.g.:\n'
                            '\t"model = Model[list[int]]([1,2,3])"\n'
                            'or indirectly in a subclass definition, e.g.:\n'
                            '\t"class MyNumberList(Model[list[int]]): ..."')

    def __setattr__(self, attr: str, value: Any) -> None:
        """Set model attributes while protecting Omnipy's root-value invariants.

        ``content`` assignments are handled specially so Omnipy can keep
        snapshot bookkeeping in sync. For wrapped non-Omnipy pydantic models,
        unknown attributes are delegated to the underlying content object.

        Args:
            attr: Attribute name to assign.
            value: Value to assign.

        Raises:
            RuntimeError: If attempting to assign an unsupported extra
                attribute on a normal Omnipy model.
        """
        if attr in ['__module__'] + list(self.__dict__.keys()) and attr not in [ROOT_KEY]:
            super().__setattr__(attr, value)
        else:
            match (attr):
                case 'content':
                    content_prop = getattr(self.__class__, attr)
                    old_content_id = id(content_prop.__get__(self))
                    is_new_content = id(value) != old_content_id

                    if is_new_content:
                        content_prop.__set__(self, value)

                        if self.config.model.interactive and self.has_snapshot():
                            self.snapshot_holder.schedule_deepcopy_content_ids_for_deletion(
                                old_content_id)
                case 'repr_state':
                    prop = getattr(self.__class__, attr)
                    prop.__set__(self, value)
                case _:
                    if self._is_non_omnipy_pydantic_model():
                        self._special_method(
                            '__setattr__',
                            MethodInfo(state_changing=True, returns_same_type=YesNoMaybe.NO),
                            attr,
                            value)
                    else:
                        raise RuntimeError('Model does not allow setting of extra attributes')

    def _special_method(  # noqa: C901
            self, name: str, info: MethodInfo, *args: object, **kwargs: object) -> object:
        """Execute a proxied special method against the wrapped content object.

        This helper centralizes Omnipy's logic for rollback handling,
        validation of state-changing operations, and conversion of returned
        values back into model instances when appropriate.

        Args:
            name: Special-method name to invoke.
            info: Metadata describing mutability and return-type expectations.
            *args: Positional arguments forwarded to the special method.
            **kwargs: Keyword arguments forwarded to the special method.

        Returns:
            object: Result of the proxied operation, possibly wrapped back into a
                model.
        """

        if info.state_changing:

            def _call_special_method_and_return_self_if_inplace(*inner_args: object,
                                                                **inner_kwargs: object) -> object:
                """Call the proxied method and preserve ``self`` for in-place ops.

                Args:
                    *inner_args: Positional arguments passed to the proxied
                        special method.
                    **inner_kwargs: Keyword arguments passed to the proxied
                        special method.

                Returns:
                    object: Operation result, or ``self`` for in-place mutations.
                """
                return_val = self._call_special_method(name, *inner_args, **inner_kwargs)

                # In-place operators should return self, which here includes the wrapping Model obj
                # The following is to avoid _convert_to_model_if_reasonable() to be called below,
                # which would otherwise create a new Model instance and return it
                if id(return_val) == id(self.content):  # in-place operator, e.g. model += 1
                    return_val = self

                return return_val

            reset_solution = self._prepare_reset_solution_take_snapshot_if_needed().reset_solution
            with reset_solution:
                ret = _call_special_method_and_return_self_if_inplace(*args, **kwargs)
                if ret is NotImplemented:
                    return ret

                self._validate_and_set_value(
                    new_content=self.content,
                    reset_solution=reset_solution,
                )

        elif name == '__iter__' and isinstance(self, Iterable) and not hasattr(self, 'keys'):
            _per_element_model_generator = self._get_convert_full_element_model_generator(
                cast(Iterable, self.content),  # level_up_type_arg_idx=0,
            )
            return _per_element_model_generator()
        else:
            ret = self._call_special_method(name, *args, **kwargs)
            if ret is NotImplemented:
                return ret

            if info.state_changing:
                self.validate_content()

        if id(ret) != id(self) and info.returns_same_type:
            level_up = False
            if name == '__getitem__':
                assert len(args) == 1
                if not isinstance(args[0], slice) and not is_non_str_byte_iterable(args[0]):
                    level_up = True

            # We can do this with some ease of mind as all the methods except '__getitem__' with
            # integer argument are supposed to possibly return a result of the same type.
            ret = self._convert_to_model_if_reasonable(
                ret,
                level_up=level_up,
                raise_validation_errors=(info.returns_same_type == YesNoMaybe.YES),
            )

        return ret

    def _call_special_method(  # noqa: C901
            self,
            name: str,
            *args: object,
            **kwargs: object,
    ) -> object:
        content = self.content

        has_add_method = self._content_obj_hasattr('__add__')
        has_radd_method = self._content_obj_hasattr('__radd__')
        has_iadd_method = self._content_obj_hasattr('__iadd__')

        if name == '__add__' and has_add_method:

            def _add(other) -> object:
                """Add another value to the wrapped content.

                Args:
                    other: Value to add.

                Returns:
                    object: Result of the underlying addition.
                """
                # try:
                #     return content.__add__(self.__class__(other).content)
                # except ValidationError:
                return content.__add__(other)  # type: ignore[operator]

            # return _add_new_other_model(*args, **kwargs)
            method = _add
            return self._call_single_arg_method_with_model_converted_other_first(
                name, method, *args, model_converted_other_method=None, **kwargs)

        elif name == '__radd__' and (has_radd_method or has_add_method):

            def _radd(other) -> object:
                """Perform reflected addition against the wrapped content.

                Args:
                    other: Left-hand operand supplied by Python's dispatch.

                Returns:
                    object: Result of the reflected addition.
                """
                if has_radd_method:
                    ret = content.__radd__(other)  # type: ignore[attr-defined]
                    if ret is NotImplemented and has_add_method:
                        return content.__add__(other)  # type: ignore[operator]
                    return ret
                else:
                    return content.__add__(other)  # type: ignore[operator]

            def _radd_model_converted_other(other) -> object:
                other_content = self.__class__(other).content
                if has_radd_method:
                    ret = content.__radd__(other_content)  # type: ignore[attr-defined]
                    if ret is NotImplemented and has_add_method:
                        return other_content.__add__(content)  # type: ignore[operator]
                    return ret
                else:
                    return other_content.__add__(content)  # type: ignore[operator]

            method = _radd
            model_converted_other_method = _radd_model_converted_other
            return self._call_single_arg_method_with_model_converted_other_first(
                name,
                method,
                *args,
                model_converted_other_method=model_converted_other_method,
                **kwargs,
            )

        elif name == '__iadd__' and (has_iadd_method or has_add_method):

            def _iadd(other) -> object:
                """Perform in-place addition on the wrapped content.

                Args:
                    other: Value to add in place.

                Returns:
                    object: Result of the underlying in-place addition.
                """
                if has_iadd_method:
                    ret = content.__iadd__(other)  # type: ignore[attr-defined]
                    if ret is NotImplemented and has_add_method:
                        return content.__add__(other)  # type: ignore[operator]
                    return ret
                else:
                    return content.__add__(other)  # type: ignore[operator]

            method = _iadd
            return self._call_single_arg_method_with_model_converted_other_first(
                name, method, *args, model_converted_other_method=None, **kwargs)
        else:
            try:
                method = cast(Callable, self._getattr_from_content_obj(name))
            except AttributeError as e:
                if name in ('__int__', '__float__', '__complex__'):
                    raise ValueError from e
                if name == '__len__':
                    raise TypeError(f"object of type '{self.__class__.__name__}' has no len()")
                else:
                    return NotImplemented

            if name == '__hash__' and method is None:
                raise TypeError(f'unhashable type: {self.__class__.__name__}')

            if name in ['__setitem__', '__setattr__']:
                key, value = args
                _, value = prepare_value_for_validation_if_dataset_or_model(value)
                args = (key, value)

                self_convert_args_if_failure = False
            else:
                self_convert_args_if_failure = True

            if name == '__getitem__' and is_model_instance(content):
                # If propagating a __getitem__ to a nested model, propagate
                # also the `dynamically_convert_elements_to_models` setting
                # as it is activated only at the innermost level (when
                # content is no longer a Model.
                reset_dyn_convert_els_to_models = False
            else:
                reset_dyn_convert_els_to_models = True

            return self._call_method(
                method,
                self_convert_args_if_failure,
                reset_dyn_convert_els_to_models,
                *args,
                **kwargs,
            )

    def _call_single_arg_method_with_model_converted_other_first(
        self,
        name: str,
        method: Callable,
        *args: object,
        model_converted_other_method: Callable | None = None,
        **kwargs: object,
    ):
        """Call a binary method, preferring model-converted operands first.

        Args:
            name: Method name used for error reporting.
            method: Fallback callable operating on the original operand.
            *args: Single positional operand.
            model_converted_other_method: Optional callable that performs the
                operation after converting the operand to this model type.
            **kwargs: Keyword arguments, which are not supported.

        Returns:
            object: Result of the operation or ``NotImplemented`` if Python
                dispatch should continue.

        Raises:
            TypeError: If the argument count or keyword usage is invalid.
        """
        if len(args) != 1:
            raise TypeError(f'expected 1 argument, got {len(args)}')

        if len(kwargs) > 0:
            raise TypeError(f'method {name} takes no keyword arguments')

        arg = args[0]

        try:
            try:
                if model_converted_other_method:
                    return model_converted_other_method(arg)
                else:
                    return method(self.__class__(arg).content, **kwargs)
            except (ValidationError, TypeError):
                # TODO: Add debug logging for hidden validation and other exceptions e.g. when
                #       concatenating `Model[int](123) + '234.'` (gives TypeError:
                #       unsupported operand type(s) for +: 'Model[int]' and 'str'). ?
                #       `Model[int](123) + '234'` works fine, returns `Model[int]('357')`.
                return method(arg)
        except TypeError:
            return NotImplemented

    def _call_method(  # noqa: C901
        self,
        method: Callable,
        self_convert_args_if_failure: bool,
        reset_dyn_convert_els_to_models: bool,
        *args: object,
        **kwargs: object,
    ):
        """Call a wrapped method with optional argument conversion fallback.

        Args:
            method: Bound content method to invoke.
            self_convert_args_if_failure: Whether to retry with operands coerced
                through this model class after a failed direct call.
            *args: Positional arguments for the method.
            **kwargs: Keyword arguments for the method.

        Returns:
            object: Result of the wrapped call.

        Raises:
            TypeError: Re-raised when both direct and converted calls fail due to
                type mismatch.
        """
        with hold_and_reset_prev_attrib_value(
                self.config.model,
                'dynamically_convert_elements_to_models',
        ):
            if reset_dyn_convert_els_to_models:
                self.config.model.dynamically_convert_elements_to_models = False

            try:
                ret = method(*args, **kwargs)
                # TODO: Do not call methods with model_converted_args where
                #       it does not make sense, e.g. by adding a field
                #       possibly_self_type_as_input in `MethodInfo`
            except TypeError as type_exc:
                if not self_convert_args_if_failure:
                    raise
                try:
                    ret = self._call_method_with_model_converted_args(method, *args, **kwargs)
                except ValidationError:
                    raise type_exc

            if ret is NotImplemented:
                if self_convert_args_if_failure:
                    try:
                        ret = self._call_method_with_model_converted_args(method, *args, **kwargs)
                    except ValidationError:
                        pass

            return ret

    def _call_method_with_model_converted_args(
        self,
        method: Callable,
        *args: object,
        **kwargs: object,
    ):
        model_args = [self.__class__(arg).content for arg in args]
        return method(*model_args, **kwargs)

    def _get_convert_full_element_model_generator(
        self,
        elements: Iterable,
    ) -> Callable[..., Generator]:
        """Build a generator factory that wraps yielded elements as models.

        Args:
            elements: Iterable whose yielded values should be converted.

        Returns:
            Callable[..., Generator]: Zero-argument generator factory yielding
                converted elements.
        """
        def _convert_full_element_model_generator(elements=elements):
            """Yield model-converted elements from a captured iterable.

            Args:
                elements: Iterable captured from the enclosing scope.

            Returns:
                Generator: Generator yielding per-element model conversions.
            """
            for el in elements:
                yield self._convert_to_model_if_reasonable(el, level_up=True)

        return _convert_full_element_model_generator

    def _get_convert_element_value_model_generator(self,
                                                   elements: Iterable) -> Callable[..., Generator]:
        """Build a generator factory that wraps mapping values as models.

        Args:
            elements: Iterable of key-value pairs whose values should be
                converted.

        Returns:
            Callable[..., Generator]: Zero-argument generator factory yielding
                pairs with converted values.
        """
        def _convert_element_value_model_generator(elements=elements):
            """Yield key-value pairs with their values converted to models.

            Args:
                elements: Iterable of key-value pairs captured from the enclosing
                    scope.

            Returns:
                Generator: Generator yielding pairs with converted values.
            """
            for el in elements:
                yield (
                    el[0],
                    self._convert_to_model_if_reasonable(el[1], level_up=True),
                )

        return _convert_element_value_model_generator

    def _convert_to_model_if_reasonable(  # noqa: C901
        self,
        ret: Mapping[_KeyT, _ValT] | Iterable[_ValT] | _ReturnT | _RootT,
        level_up: bool = False,
        raise_validation_errors: bool = False,
    ) -> 'Model[_KeyT] | Model[_ValT] | Model[tuple[_KeyT, _ValT]] | Model[_ReturnT] | Model[_RootT] | _ReturnT':  # noqa: E501
        """Wrap a returned value in a suitable model when type information fits.

        Args:
            ret: Returned value from a proxied content operation.
            level_up: When ``True``, attempt element-level wrapping rather than
                whole-container wrapping.
            raise_validation_errors: When ``True``, propagate validation errors
                encountered during attempted wrapping.

        Returns:
            Model[_KeyT] | Model[_ValT] | Model[tuple[_KeyT, _ValT]] |
            Model[_ReturnT] | Model[_RootT] | _ReturnT: Wrapped model when a
            reasonable conversion exists, otherwise the original value.
        """
        from omnipy.data._typing.helpers import all_model_type_variants

        if level_up and not self.config.model.dynamically_convert_elements_to_models:
            ...
        else:
            for type_to_check in all_model_type_variants(self):
                plain_type_to_check = ensure_plain_type(type_to_check)
                if plain_type_to_check in (ForwardRef, TypeVar, None):
                    continue

                if level_up:  # from above: dynamically_convert_elements_to_models == True
                    type_args = get_args(type_to_check)
                    if type_args:
                        # Assuming last type argument is the type of value of the container
                        value_arg_type = type_args[-1]

                        for level_up_type_to_check in all_type_variants(value_arg_type):
                            level_up_type_to_check = self._fix_tuple_type_from_args(
                                level_up_type_to_check)
                            # Only non-Models content considered for dynamic conversion
                            if not is_model_instance(ret) and self._is_instance_or_literal(
                                    ret,
                                    ensure_plain_type(level_up_type_to_check),
                                    level_up_type_to_check,
                            ):
                                try:
                                    return Model[level_up_type_to_check](ret)  # type: ignore
                                except ValidationError:
                                    if raise_validation_errors:
                                        raise
                                except TypeError:
                                    pass

                else:
                    if self._is_instance_or_literal(
                            ret,
                            plain_type_to_check,
                            type_to_check,
                    ):
                        try:
                            return self.__class__(ret)
                        except ValidationError:
                            if raise_validation_errors:
                                raise
                        except TypeError:
                            pass

        return cast(_ReturnT, ret)

    @staticmethod
    def _is_instance_or_literal(obj: object, plain_type: type, raw_type: type | GenericAlias):
        """Check a value against either a runtime type or literal alternatives.

        Args:
            obj: Value to test.
            plain_type: Runtime type to check directly.
            raw_type: Original type expression, possibly a ``Literal``.

        Returns:
            bool: ``True`` when ``obj`` matches the requested type semantics.
        """
        if plain_type is Literal:
            args = get_args(raw_type)
            for arg in args:
                if obj == arg:
                    return True
            return False
        else:
            return lenient_isinstance(obj, plain_type)

    def _fix_tuple_type_from_args(
        self, level_up_type_to_check: type | GenericAlias | tuple[type | GenericAlias, ...]
    ) -> type | GenericAlias:
        """Normalize tupled type arguments into a usable tuple type expression.

        Args:
            level_up_type_to_check: Candidate element type or tuple of type
                arguments.

        Returns:
            type | GenericAlias: Normalized type expression suitable for model
                construction.
        """
        if isinstance(level_up_type_to_check, tuple):
            match len(level_up_type_to_check):
                case 1:
                    return level_up_type_to_check[0]
                case _:
                    return tuple[level_up_type_to_check]  # type: ignore[valid-type]
        else:
            return level_up_type_to_check

    if not TYPE_CHECKING:

        def __getattr__(self, attr: str) -> Any:
            """Proxy missing attributes and methods to the wrapped content object.

            Omnipy uses this hook to expose operations of the wrapped root value
            while still validating state-changing calls and converting returned
            elements back into models when appropriate.

            Args:
                attr: Attribute name requested on the model.

            Returns:
                The proxied attribute or wrapped method from the underlying
                content object.

            Raises:
                AttributeError: If the wrapped content object does not define
                    ``attr``.
            """
            if self._is_non_omnipy_pydantic_model() and self._content_obj_hasattr(attr):
                self._validate_and_set_value(self.content)

            content_attr = self._getattr_from_content_obj(attr)

            if inspect.isroutine(content_attr):
                method_info = self.__class__._get_special_methods_info_dict().get(attr)
                is_read_only_method = (
                    method_info and not method_info.state_changing
                    or attr in ('items', 'values', 'keys'))

                if not is_read_only_method:
                    reset_solution = \
                        self._prepare_reset_solution_take_snapshot_if_needed().reset_solution
                    new_content_attr: Callable = cast(Callable,
                                                      self._getattr_from_content_obj(attr))

                    def _validate_content(ret: Any):
                        """Re-validate content after a proxied mutating method call.

                        Args:
                            ret: Raw return value from the wrapped content
                                method.

                        Returns:
                            Any: Possibly model-converted return value.

                        Raises:
                            ValidationError: If the wrapped mutation leaves the
                                content in an invalid state.
                        """
                        self._validate_and_set_value(self.content, reset_solution=reset_solution)
                        return self._convert_to_model_if_reasonable(
                            ret,
                            level_up=False,
                            raise_validation_errors=False,
                        )

                    content_attr = add_callback_after_call(new_content_attr,
                                                           _validate_content,
                                                           reset_solution)

            if attr in ('values', 'items'):
                match attr:
                    case 'values':
                        _model_generator = self._get_convert_full_element_model_generator(())
                    case 'items':
                        _model_generator = self._get_convert_element_value_model_generator(())

                content_attr = add_callback_after_call(
                    cast(Callable, content_attr),
                    _model_generator,
                    no_context,
                )

            return content_attr

    def _is_non_omnipy_pydantic_model(self) -> bool:
        return is_non_omnipy_pydantic_model(self.content)

    def _content_obj_hasattr(self, attr) -> object:
        return hasattr(self.content, attr)

    def _getattr_from_content_obj(self, attr) -> object:
        return getattr(self.content, attr)

    def _getattr_from_content_cls(self, attr) -> object:
        return getattr(self.content.__class__, attr)

    # def _get_real_content(self) -> object:
    #     if is_model_instance(self.content):
    #         return self.content.content
    #     else:
    #         return self.content

    def __eq__(self, other: object) -> bool:
        """Compare two models by concrete class and wrapped content.

        Args:
            other: Object to compare with this model.

        Returns:
            ``True`` when ``other`` is the same concrete model class and its
            content compares equal.
        """
        if is_model_instance(other):
            return (self.__class__ == other.__class__ and all_equals(self.content, other.content))
            # and self.to_data() == other.to_data()  # last line is just in case
        else:
            return False

    def __bool__(self):
        if self.content:
            return True
        else:
            return False

    def __call__(self, *args: object, **kwargs: object) -> object:
        if not self._content_obj_hasattr('__call__'):
            raise TypeError(f"'{self.__class__.__name__}' object is not callable")
        return self._special_method(
            '__call__',
            MethodInfo(state_changing=True, returns_same_type=YesNoMaybe.NO),
            *args,
            **kwargs)

    def __repr_args__(self):
        """Provide the root value to pydantic's representation machinery.

        Returns:
            Representation arguments describing the wrapped content.
        """
        return [(None, self.content)]

config property

config: IsDataConfig

Return the data configuration shared by the owning data-class family.

RETURNS DESCRIPTION
IsDataConfig

Shared configuration object used by related models and datasets.

TYPE: IsDataConfig

content property writable

content: _RootT

Access the parsed root value stored by the model.

RETURNS DESCRIPTION
_RootT

The current validated root value.

reactive_objects property

reactive_objects: IsReactiveObjects | None

Return the reactive-object registry attached to this data-class family.

snapshot property

snapshot: _RootT

Return the validated snapshot currently tracked for this model.

RETURNS DESCRIPTION
_RootT

The snapshot value stored for the current model instance.

RAISES DESCRIPTION
AssertionError

If no snapshot has been taken yet.

snapshot_holder property

Return the snapshot holder coordinating copy-based change tracking.

Config

Configure pydantic behavior for Omnipy models.

This nested configuration class enables Omnipy's relaxed runtime model behavior, including arbitrary wrapped types, eager validation, and enum value serialization.

ATTRIBUTE DESCRIPTION
arbitrary_types_allowed

Allows root values that are not native pydantic field types.

validate_all

Validates all fields during model creation.

smart_union

Enables pydantic's smarter union parsing behavior.

use_enum_values

Serializes enums by their values.

Source code in src/omnipy/data/model.py
class Config:
    """Configure pydantic behavior for Omnipy models.

    This nested configuration class enables Omnipy's relaxed runtime model
    behavior, including arbitrary wrapped types, eager validation, and enum
    value serialization.

    Attributes:
        arbitrary_types_allowed: Allows root values that are not native
            pydantic field types.
        validate_all: Validates all fields during model creation.
        smart_union: Enables pydantic's smarter union parsing behavior.
        use_enum_values: Serializes enums by their values.
    """
    arbitrary_types_allowed = True
    validate_all = True
    # validate_assignment = True
    smart_union = True
    # json_loads = orjson.loads
    # json_dumps = orjson_dumps
    use_enum_values = True

arbitrary_types_allowed class-attribute instance-attribute

arbitrary_types_allowed = True

smart_union class-attribute instance-attribute

smart_union = True

use_enum_values class-attribute instance-attribute

use_enum_values = True

validate_all class-attribute instance-attribute

validate_all = True

__init__

__init__(
    value: _RootT | object | UndefinedType = Undefined,
    *,
    __root__: _RootT | object | UndefinedType = Undefined,
    **kwargs: _RootT | object,
) -> None

Parse input into the concrete model's root value.

The constructor accepts either a direct root value, the pydantic-style __root__ keyword, or keyword pairs for dict-like models. Omnipy also accepts datasets, other models, and plain pydantic models as input and converts them to raw data before validation.

PARAMETER DESCRIPTION
value

Root value to parse.

TYPE: _RootT | object | UndefinedType DEFAULT: Undefined

__root__

Alternative explicit root value.

TYPE: _RootT | object | UndefinedType DEFAULT: Undefined

**kwargs

Mapping-style root content for dict-like models.

TYPE: _RootT | object DEFAULT: {}

RAISES DESCRIPTION
AssertionError

If root data is supplied through more than one input path.

ValidationError

If the provided data cannot be parsed as this model's declared type.

Source code in src/omnipy/data/model.py
def __init__(  # noqa: C901
    self,
    value: _RootT | object | UndefinedType = Undefined,
    *,
    __root__: _RootT | object | UndefinedType = Undefined,
    **kwargs: _RootT | object,
) -> None:
    """Parse input into the concrete model's root value.

    The constructor accepts either a direct root value, the pydantic-style
    ``__root__`` keyword, or keyword pairs for dict-like models. Omnipy also
    accepts datasets, other models, and plain pydantic models as input and
    converts them to raw data before validation.

    Args:
        value: Root value to parse.
        __root__: Alternative explicit root value.
        **kwargs: Mapping-style root content for dict-like models.

    Raises:
        AssertionError: If root data is supplied through more than one input
            path.
        ValidationError: If the provided data cannot be parsed as this
            model's declared type.
    """
    super_kwargs: dict[str, _RootT] = {}
    num_root_vals = 0

    if value is not Undefined:
        super_kwargs[ROOT_KEY] = cast(_RootT, value)
        num_root_vals += 1

    if __root__ is not Undefined:
        super_kwargs[ROOT_KEY] = cast(_RootT, __root__)
        num_root_vals += 1

    if kwargs:
        super_kwargs[ROOT_KEY] = cast(_RootT, kwargs)
        kwargs = {}
        num_root_vals += 1

    assert num_root_vals <= 1, 'Not allowed to provide root data in more than one argument'

    if self._get_root_field().default_factory is undefined_default_factory:
        self._get_root_field().default_factory = self._get_default_factory()

    dataset_or_model_as_input = False
    if ROOT_KEY in super_kwargs:
        try:
            dataset_or_model_as_input, value = \
                prepare_value_for_validation_if_dataset_or_model(super_kwargs[ROOT_KEY])
        except Exception as exc:
            val_exc = ValueError(f'Failed to prepare value for validation: {exc}')
            raise ValidationError(
                [pyd.ErrorWrapper(exc, loc=ROOT_KEY), pyd.ErrorWrapper(val_exc, loc=ROOT_KEY)],
                self.__class__)
        if dataset_or_model_as_input:
            super_kwargs[ROOT_KEY] = cast(_RootT, value)

    self._init(super_kwargs, **kwargs)

    try:
        self._primary_validation(super_kwargs)
    except ValidationError:
        if dataset_or_model_as_input:
            self._secondary_validation_from_data(super_kwargs)
        else:
            raise

    if not self.__class__.__doc__:
        self._set_standard_field_description()

absorb_and_replace

absorb_and_replace(other: Model)

Replace this model's content with data parsed from another model.

PARAMETER DESCRIPTION
other

Source model whose serialized data should be absorbed.

TYPE: Model

Source code in src/omnipy/data/model.py
def absorb_and_replace(self, other: 'Model'):
    """Replace this model's content with data parsed from another model.

    Args:
        other: Source model whose serialized data should be absorbed.
    """
    self.from_data(other.to_data())

browse

browse(
    *,
    width: pyd.NonNegativeInt | None = None,
    height: pyd.NonNegativeInt | None = None,
    tab: pyd.NonNegativeInt = 4,
    indent: pyd.NonNegativeInt = 2,
    printer: PrettyPrinterLib.Literals = "auto",
    syntax: SyntaxLanguageSpec.Literals | str = "auto",
    freedom: pyd.NonNegativeFloat | None = 2.5,
    debug: bool = False,
    ui: UserInterfaceType.Literals = "auto",
    system: DisplayColorSystem.Literals = "auto",
    style: AllColorStyles.Literals | str = "auto",
    dark: typing.Literal["auto", True, False] = "auto",
    bg: bool = False,
    fonts: tuple[str, ...] = ("Menlo", "DejaVu Sans Mono", "Consolas", "Courier New", "monospace"),
    font_size: pyd.NonNegativeFloat | None = 14,
    font_weight: pyd.NonNegativeInt | None = 400,
    line_height: pyd.NonNegativeFloat | None = 1.25,
    h_overflow: HorizontalOverflowMode.Literals = "ellipsis",
    v_overflow: VerticalOverflowMode.Literals = "ellipsis_bottom",
    panel: PanelDesign.Literals = "table",
    title_at_top: bool = True,
    max_title_height: MaxTitleHeight.Literals = -1,
    min_panel_width: pyd.NonNegativeInt = 3,
    min_crop_width: pyd.NonNegativeInt = 33,
    use_min_crop_width: bool = False,
    max_panels_hor: pyd.NonNegativeInt | None = 9,
    max_nesting_depth: pyd.NonNegativeInt | None = 3,
    justify: Justify.Literals = "left",
) -> None

Opens the model or dataset in a browser, if possible.

For models, this is a detailed view of the model's content, and for datasets this is a detailed view of each model contained in the dataset, one model per browser tab.

PARAMETER DESCRIPTION
width

Width in characters of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

height

Height in lines of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

tab

Number of spaces to use for each tab.

TYPE: NonNegativeInt DEFAULT: 4

indent

Number of spaces to use for each indentation level.

TYPE: NonNegativeInt DEFAULT: 2

printer

Library to use for pretty printing.

TYPE: PrettyPrinterLib.Literals DEFAULT: 'auto'

syntax

Syntax language for code highlighting. Supported lexers are defined in SyntaxLanguageSpec. For non-supported styles, the user can specify a string with the Pygments lexer name. For this to work, the lexer must be registered in the Pygments library.

TYPE: SyntaxLanguageSpec.Literals | str DEFAULT: 'auto'

freedom

Parameter that controls the level of freedom for formatted text to follow the geometry of the frame size (=total available area) in a proportional manner. If the proportional freedom is 0 (the lowest), then the output area must not in any case be proportionally wider that the frame (i.e. a 16/9 frame will only produce output that is 16/9 or narrower). Larger values of proportional freedom allow the output to be proportionally wider than the total available frame, to a degree that relates to the size difference between the frame and the content (larger difference gives more freedom). The default value of 2.5 is a good compromise between readability/aesthetics and good use of the screen estate. If None, the freedom is unlimited (i.e. proportionality is not taken into account at all).

TYPE: float | None DEFAULT: 2.5

debug

When True, enables additional debugging information in the output, such as the hierarchy of the Model objects. Currently, only Python pretty printers support debug=True. Hence, enabling debug mode will automatically set the printer to the default Python pretty printer if the printer config value is not already set.

TYPE: bool DEFAULT: False

ui

Type of user interface for which the output should being prepared. The user interface describes the technical solutions available for interacting with the user, encompassing the support available for displaying output as well as how the user interacts with the library (including the type of interactive interpreter used, if any).

TYPE: UserInterfaceType.Literals DEFAULT: 'auto'

system

Color system to use for terminal output. The default is AUTO, which automatically detects the color system based on particular environment variables. If color capabilities are not detected, the output will be in black and white. If the color system of a modern consoles/terminal is not auto-detected (which is the case for e.g. the PyCharm console), the user might want to set the color system manually to ANSI_RGB to force color output.

TYPE: ColorSystem.Literals DEFAULT: 'auto'

style

Color style/theme for syntax highlighting and other display elements. Supported styles are defined in AllColorStyles. For non-supported styles, the user can specify a string with the Pygments style name. For this to work, the style must be registered in the Pygments library. If style is AUTO or any of the other RecommendedColorStyles, the style is automatically selected from the RecommendedColorStyles based on the detected user interface, the color system, and whether the background is dark or not.

TYPE: AllColorStyles.Literals | str DEFAULT: 'auto'

dark

Whether the background color of the output is dark. This is used to determine the appropriate color scheme for syntax highlighting. The default is AUTO, which automatically tries to detect whether the background is dark. Capability of auto-detection depends on the user interface.

TYPE: DarkBackground.Literals DEFAULT: 'auto'

bg

If False, uses transparent background for the output. In the case of terminal output, the background color will be the current background color of the terminal. For HTML output, the background color will be automatically set to pure black or pure white, depending on the luminosity of the foreground color.

TYPE: bool DEFAULT: False

fonts

Font families to use in HTML output, in order of preference (empty tuple for browser default).

TYPE: Tuple[str, ...] DEFAULT: ('Menlo', 'DejaVu Sans Mono', 'Consolas', 'Courier New', 'monospace')

font_size

Font size in pixels for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 14

font_weight

Font weight for HTML output (None for browser default).

TYPE: NonNegativeInt | None DEFAULT: 400

line_height

Line height multiplier for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 1.25

h_overflow

How to handle text that exceeds the width.

TYPE: HorizontalOverflowMode.Literals DEFAULT: 'ellipsis'

v_overflow

How to handle text that exceeds the height.

TYPE: VerticalOverflowMode.Literals DEFAULT: 'ellipsis_bottom'

panel

Visual design of the panel used as container for the output. Only TABLE is currently supported, which displays the output in a table-like grid.

TYPE: PanelDesign.Literals DEFAULT: 'table'

title_at_top

Whether panel titles will be displayed over the panel content (True) or below the content (False)

TYPE: bool DEFAULT: True

max_title_height

Maximum height of the panel title. If AUTO, the height is determined by the content of the title, up to a maximum of two lines. If ZERO, the title is not displayed at all. If ONE or TWO, the title is displayed with a fixed height of max one or two lines, respectively.

TYPE: MaxTitleHeight.Literals DEFAULT: -1

min_panel_width

Minimum width in characters per panel.

TYPE: NonNegativeInt DEFAULT: 3

min_crop_width

Minimum cropping width in characters for panels in cases where more than one panel are to be displayed. This is for instance used to calculate the number of models to display in a Dataset peek(). Only applied if use_min_crop_width is set to True. min_crop_width must be equal to or larger than min_panel_width.

TYPE: NonNegativeInt DEFAULT: 33

use_min_crop_width

Whether the min_crop_width value should be considered in cases where more than one panel are to be displayed, potentially reducing the number of displayed panels.

TYPE: bool DEFAULT: False

max_panels_hor

Maximum number of panels to display horizontally side-by-side at the top level. This value also acts as a ceiling for nested panels; nested panels cannot exceed this limit even if the constant MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED is set to a higher value. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 9

max_nesting_depth

Maximum levels of nested panels to display. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 3

justify

Justification mode for the panel if inside a layout panel. This is only used for the panel content.

TYPE: Justify.Literals DEFAULT: 'left'

Source code in src/omnipy/data/_mixins/display.py
def browse(self, **kwargs) -> None:
    # %% Original docstring (managed by expand_docstr_macros.py) %%
    # {{BROWSE_SUMMARY}}
    #
    # {{BROWSE_DESCRIPTION}}
    #
    # {{DISPLAY_METHOD_ARGS}}
    #
    """Opens the model or dataset in a browser, if possible.

    For models, this is a detailed view of the model's content,
    and for datasets this is a detailed view of each model
    contained in the dataset, one model per browser tab.

    Args:
        width (NonNegativeInt | None):
            Width in characters of the output area (None for
            auto-detect based on available display dimensions).
        height (NonNegativeInt | None):
            Height in lines of the output area (None for
            auto-detect based on available display dimensions).
        tab (NonNegativeInt):
            Number of spaces to use for each tab.
        indent (NonNegativeInt):
            Number of spaces to use for each indentation level.
        printer (PrettyPrinterLib.Literals):
            Library to use for pretty printing.
        syntax (SyntaxLanguageSpec.Literals | str):
            Syntax language for code highlighting. Supported
            lexers are defined in SyntaxLanguageSpec. For
            non-supported styles, the user can specify a string
            with the Pygments lexer name. For this to work, the
            lexer must be registered in the Pygments library.
        freedom (float | None):
            Parameter that controls the level of freedom for
            formatted text to follow the geometry of the frame
            size (=total available area) in a proportional manner.
            If the proportional freedom is 0 (the lowest), then
            the output area must not in any case be proportionally
            wider that the frame (i.e. a 16/9 frame will only
            produce output that is 16/9 or narrower). Larger
            values of proportional freedom allow the output to be
            proportionally wider than the total available frame,
            to a degree that relates to the size difference
            between the frame and the content (larger difference
            gives more freedom). The default value of 2.5 is a
            good compromise between readability/aesthetics and
            good use of the screen estate. If None, the freedom is
            unlimited (i.e. proportionality is not taken into
            account at all).
        debug (bool):
            When True, enables additional debugging information in
            the output, such as the hierarchy of the Model
            objects. Currently, only Python pretty printers support
            debug=True. Hence, enabling debug mode will
            automatically set the printer to the default Python
            pretty printer if the `printer` config value is not
            already set.
        ui (UserInterfaceType.Literals):
            Type of user interface for which the output should
            being prepared. The user interface describes the
            technical solutions available for interacting with the
            user, encompassing the support available for
            displaying output as well as how the user interacts
            with the library (including the type of interactive
            interpreter used, if any).
        system (ColorSystem.Literals):
            Color system to use for terminal output. The default
            is `AUTO`, which automatically detects the color
            system based on particular environment variables. If
            color capabilities are not detected, the output will
            be in black and white. If the color system of a modern
            consoles/terminal is not auto-detected (which is the
            case for e.g. the PyCharm console), the user might
            want to set the color system manually to ANSI_RGB to
            force color output.
        style (AllColorStyles.Literals | str):
            Color style/theme for syntax highlighting and other
            display elements. Supported styles are defined in
            AllColorStyles. For non-supported styles, the user can
            specify a string with the Pygments style name. For this to
            work, the style must be registered in the Pygments
            library. If style is `AUTO` or any of the other
            RecommendedColorStyles, the style is automatically
            selected from the RecommendedColorStyles based on the
            detected user interface, the color system, and whether the
            background is dark or not.
        dark (DarkBackground.Literals):
            Whether the background color of the output is dark.
            This is used to determine the appropriate color scheme
            for syntax highlighting. The default is AUTO, which
            automatically tries to detect whether the background
            is dark. Capability of auto-detection depends on the
            user interface.
        bg (bool):
            If False, uses transparent background for the output.
            In the case of terminal output, the background color
            will be the current background color of the terminal.
            For HTML output, the background color will be
            automatically set to pure black or pure white,
            depending on the luminosity of the foreground color.
        fonts (Tuple[str, ...]):
            Font families to use in HTML output, in order of
            preference (empty tuple for browser default).
        font_size (NonNegativeFloat | None):
            Font size in pixels for HTML output (None for browser
            default).
        font_weight (NonNegativeInt | None):
            Font weight for HTML output (None for browser
            default).
        line_height (NonNegativeFloat | None):
            Line height multiplier for HTML output (None for
            browser default).
        h_overflow (HorizontalOverflowMode.Literals):
            How to handle text that exceeds the width.
        v_overflow (VerticalOverflowMode.Literals):
            How to handle text that exceeds the height.
        panel (PanelDesign.Literals):
            Visual design of the panel used as container for the
            output. Only `TABLE` is currently supported, which
            displays the output in a table-like grid.
        title_at_top (bool):
            Whether panel titles will be displayed over the panel
            content (True) or below the content (False)
        max_title_height (MaxTitleHeight.Literals):
            Maximum height of the panel title. If `AUTO`, the
            height is determined by the content of the title, up
            to a maximum of two lines. If `ZERO`, the title is not
            displayed at all. If `ONE` or `TWO`, the title is
            displayed with a fixed height of max one or two lines,
            respectively.
        min_panel_width (NonNegativeInt):
            Minimum width in characters per panel.
        min_crop_width (NonNegativeInt):
            Minimum cropping width in characters for panels in
            cases where more than one panel are to be displayed.
            This is for instance used to calculate the number of
            models to display in a Dataset peek(). Only applied if
            `use_min_crop_width` is set to `True`.
            `min_crop_width` must be equal to or larger than
            `min_panel_width`.
        use_min_crop_width (bool):
            Whether the `min_crop_width` value should be
            considered in cases where more than one panel are to
            be displayed, potentially reducing the number of
            displayed panels.
        max_panels_hor (NonNegativeInt | None):
            Maximum number of panels to display horizontally
            side-by-side at the top level. This value also acts as
            a ceiling for nested panels; nested panels cannot
            exceed this limit even if the constant
            `MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED` is set to a
            higher value. If None, there is no limit.
        max_nesting_depth (NonNegativeInt | None):
            Maximum levels of nested panels to display. If None,
            there is no limit.
        justify (Justify.Literals):
            Justification mode for the panel if inside a layout
            panel. This is only used for the panel content.
    """
    self._browse(**kwargs)

clone_model_cls classmethod

clone_model_cls(new_model_cls_name: str) -> type[Self]

Create a subclass clone of this concrete model class.

PARAMETER DESCRIPTION
new_model_cls_name

Name to assign to the cloned class.

TYPE: str

RETURNS DESCRIPTION
type[Self]

A new subclass with the same behavior and type binding.

Source code in src/omnipy/data/model.py
@classmethod
def clone_model_cls(cls, new_model_cls_name: str) -> type[Self]:
    """Create a subclass clone of this concrete model class.

    Args:
        new_model_cls_name: Name to assign to the cloned class.

    Returns:
        A new subclass with the same behavior and type binding.
    """
    new_model_cls = type(new_model_cls_name, (cls,), {})
    return cast(type[Self], new_model_cls)

content_validated_according_to_snapshot

content_validated_according_to_snapshot() -> bool

Report whether current content still matches the validated snapshot.

RETURNS DESCRIPTION
bool

True when the current content is still represented by the stored snapshot and does not need re-validation.

Source code in src/omnipy/data/model.py
def content_validated_according_to_snapshot(self) -> bool:
    """Report whether current content still matches the validated snapshot.

    Returns:
        ``True`` when the current content is still represented by the stored
        snapshot and does not need re-validation.
    """
    needs_validation = self.snapshot_differs_from_model(self) \
        or not self.snapshot_taken_of_same_model(self)
    return not needs_validation

copy

copy(*, deep: bool = False, **kwargs) -> Self

Copy the model while avoiding shared mutable content by default.

Omnipy overrides pydantic's copy semantics so a shallow copy still gets a shallow-copied root value instead of sharing the same mutable object.

PARAMETER DESCRIPTION
deep

When True, perform a deep copy.

TYPE: bool DEFAULT: False

**kwargs

Additional keyword arguments forwarded to pydantic's copy() implementation.

DEFAULT: {}

RETURNS DESCRIPTION
Self

A copied model instance.

Source code in src/omnipy/data/model.py
def copy(self, *, deep: bool = False, **kwargs) -> Self:
    """Copy the model while avoiding shared mutable content by default.

    Omnipy overrides pydantic's copy semantics so a shallow copy still gets
    a shallow-copied root value instead of sharing the same mutable object.

    Args:
        deep: When ``True``, perform a deep copy.
        **kwargs: Additional keyword arguments forwarded to pydantic's
            ``copy()`` implementation.

    Returns:
        A copied model instance.
    """
    pydantic_copy = pyd.GenericModel.copy(self, deep=deep, **kwargs)
    if not deep:
        # Shallow copying of the model should not share the same
        # content, as this can lead to unintentional side effects when
        # the content is mutable.
        pydantic_copy.content = copy(pydantic_copy.__dict__[ROOT_KEY])
    return pydantic_copy  # pyright: ignore[reportReturnType]

deepcopy_context

deepcopy_context(
    top_level_entry_func: Callable[[], None], top_level_exit_func: Callable[[], None]
) -> ContextManager[int]

Delegate nested deepcopy bookkeeping to the shared data-class creator.

PARAMETER DESCRIPTION
top_level_entry_func

Callback run when entering the outermost deepcopy context.

TYPE: Callable[[], None]

top_level_exit_func

Callback run when leaving the outermost deepcopy context.

TYPE: Callable[[], None]

RETURNS DESCRIPTION
ContextManager[int]

A context manager yielding the current deepcopy nesting depth.

Source code in src/omnipy/data/_data_class_creator.py
def deepcopy_context(
    self,
    top_level_entry_func: Callable[[], None],
    top_level_exit_func: Callable[[], None],
) -> ContextManager[int]:
    """Delegate nested deepcopy bookkeeping to the shared data-class creator.

    Args:
        top_level_entry_func: Callback run when entering the outermost deepcopy context.
        top_level_exit_func: Callback run when leaving the outermost deepcopy context.

    Returns:
        A context manager yielding the current deepcopy nesting depth.
    """

    return self.__class__.data_class_creator.deepcopy_context(top_level_entry_func,
                                                              top_level_exit_func)

default_repr_to_terminal_str

default_repr_to_terminal_str(ui_type: TerminalOutputUserInterfaceType.Literals) -> str

Render the default display panel as terminal text.

PARAMETER DESCRIPTION
ui_type

Terminal-oriented user interface to render for.

TYPE: TerminalOutputUserInterfaceType.Literals

RETURNS DESCRIPTION
str

The fully rendered string representation for repr()-style terminal output.

Source code in src/omnipy/data/_mixins/display.py
def default_repr_to_terminal_str(
    self,
    ui_type: TerminalOutputUserInterfaceType.Literals,
) -> str:
    """Render the default display panel as terminal text.

    Args:
        ui_type: Terminal-oriented user interface to render for.

    Returns:
        The fully rendered string representation for ``repr()``-style
        terminal output.
    """
    return self._display_according_to_ui_type(
        ui_type=ui_type,
        return_output_if_str=True,
        output_method=self._default_panel,
    )

dict

dict(*args, **kwargs) -> dict_t[str, object]
Source code in src/omnipy/data/model.py
def dict(self, *args, **kwargs) -> dict_t[str, object]:
    return {ROOT_KEY: self.to_data()}

do

do(placeholder: F) -> Any

Apply a placeholder-style callable to this model.

PARAMETER DESCRIPTION
placeholder

Callable placeholder from Omnipy's F helper.

TYPE: F

RETURNS DESCRIPTION
Any

Whatever value placeholder returns for this model instance.

Source code in src/omnipy/data/model.py
def do(self, placeholder: F) -> Any:
    """Apply a placeholder-style callable to this model.

    Args:
        placeholder: Callable placeholder from Omnipy's ``F`` helper.

    Returns:
        Whatever value ``placeholder`` returns for this model instance.
    """
    return placeholder(self)

from_data

from_data(data: Any) -> None

Parse raw Python data into this existing model instance.

PARAMETER DESCRIPTION
data

Raw data to validate and store as the model's content.

TYPE: Any

RAISES DESCRIPTION
ValidationError

If data cannot be parsed as this model's type.

Source code in src/omnipy/data/model.py
def from_data(self, data: Any) -> None:
    """Parse raw Python data into this existing model instance.

    Args:
        data: Raw data to validate and store as the model's content.

    Raises:
        ValidationError: If ``data`` cannot be parsed as this model's type.
    """
    if self.content == self._get_default_value_from_model(self.full_type()):
        self._empty_from_data(data)
    else:
        self._validate_and_set_value(data)

from_json

from_json(json_content: str) -> None

Parse JSON into this existing model instance.

PARAMETER DESCRIPTION
json_content

JSON document to parse.

TYPE: str

RAISES DESCRIPTION
ValidationError

If the JSON content does not match the model type.

Source code in src/omnipy/data/model.py
def from_json(self, json_content: str) -> None:
    """Parse JSON into this existing model instance.

    Args:
        json_content: JSON document to parse.

    Raises:
        ValidationError: If the JSON content does not match the model type.
    """
    new_model = self.parse_raw(json_content, proto=pyd.Protocol.json)
    self.content = new_model.content

full

full(
    *,
    width: pyd.NonNegativeInt | None = None,
    height: pyd.NonNegativeInt | None = None,
    tab: pyd.NonNegativeInt = 4,
    indent: pyd.NonNegativeInt = 2,
    printer: PrettyPrinterLib.Literals = "auto",
    syntax: SyntaxLanguageSpec.Literals | str = "auto",
    freedom: pyd.NonNegativeFloat | None = 2.5,
    debug: bool = False,
    ui: UserInterfaceType.Literals = "auto",
    system: DisplayColorSystem.Literals = "auto",
    style: AllColorStyles.Literals | str = "auto",
    dark: typing.Literal["auto", True, False] = "auto",
    bg: bool = False,
    fonts: tuple[str, ...] = ("Menlo", "DejaVu Sans Mono", "Consolas", "Courier New", "monospace"),
    font_size: pyd.NonNegativeFloat | None = 14,
    font_weight: pyd.NonNegativeInt | None = 400,
    line_height: pyd.NonNegativeFloat | None = 1.25,
    h_overflow: HorizontalOverflowMode.Literals = "ellipsis",
    v_overflow: VerticalOverflowMode.Literals = "ellipsis_bottom",
    panel: PanelDesign.Literals = "table",
    title_at_top: bool = True,
    max_title_height: MaxTitleHeight.Literals = -1,
    min_panel_width: pyd.NonNegativeInt = 3,
    min_crop_width: pyd.NonNegativeInt = 33,
    use_min_crop_width: bool = False,
    max_panels_hor: pyd.NonNegativeInt | None = 9,
    max_nesting_depth: pyd.NonNegativeInt | None = 3,
    justify: Justify.Literals = "left",
) -> Element | None

Display the content of the Model or Dataset in full height.

full() is a shorthand for peek(height=None) for both models and datasets. Both full-height views are automatically limited in width by the available display dimensions.

PARAMETER DESCRIPTION
width

Width in characters of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

height

Height in lines of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

tab

Number of spaces to use for each tab.

TYPE: NonNegativeInt DEFAULT: 4

indent

Number of spaces to use for each indentation level.

TYPE: NonNegativeInt DEFAULT: 2

printer

Library to use for pretty printing.

TYPE: PrettyPrinterLib.Literals DEFAULT: 'auto'

syntax

Syntax language for code highlighting. Supported lexers are defined in SyntaxLanguageSpec. For non-supported styles, the user can specify a string with the Pygments lexer name. For this to work, the lexer must be registered in the Pygments library.

TYPE: SyntaxLanguageSpec.Literals | str DEFAULT: 'auto'

freedom

Parameter that controls the level of freedom for formatted text to follow the geometry of the frame size (=total available area) in a proportional manner. If the proportional freedom is 0 (the lowest), then the output area must not in any case be proportionally wider that the frame (i.e. a 16/9 frame will only produce output that is 16/9 or narrower). Larger values of proportional freedom allow the output to be proportionally wider than the total available frame, to a degree that relates to the size difference between the frame and the content (larger difference gives more freedom). The default value of 2.5 is a good compromise between readability/aesthetics and good use of the screen estate. If None, the freedom is unlimited (i.e. proportionality is not taken into account at all).

TYPE: float | None DEFAULT: 2.5

debug

When True, enables additional debugging information in the output, such as the hierarchy of the Model objects. Currently, only Python pretty printers support debug=True. Hence, enabling debug mode will automatically set the printer to the default Python pretty printer if the printer config value is not already set.

TYPE: bool DEFAULT: False

ui

Type of user interface for which the output should being prepared. The user interface describes the technical solutions available for interacting with the user, encompassing the support available for displaying output as well as how the user interacts with the library (including the type of interactive interpreter used, if any).

TYPE: UserInterfaceType.Literals DEFAULT: 'auto'

system

Color system to use for terminal output. The default is AUTO, which automatically detects the color system based on particular environment variables. If color capabilities are not detected, the output will be in black and white. If the color system of a modern consoles/terminal is not auto-detected (which is the case for e.g. the PyCharm console), the user might want to set the color system manually to ANSI_RGB to force color output.

TYPE: ColorSystem.Literals DEFAULT: 'auto'

style

Color style/theme for syntax highlighting and other display elements. Supported styles are defined in AllColorStyles. For non-supported styles, the user can specify a string with the Pygments style name. For this to work, the style must be registered in the Pygments library. If style is AUTO or any of the other RecommendedColorStyles, the style is automatically selected from the RecommendedColorStyles based on the detected user interface, the color system, and whether the background is dark or not.

TYPE: AllColorStyles.Literals | str DEFAULT: 'auto'

dark

Whether the background color of the output is dark. This is used to determine the appropriate color scheme for syntax highlighting. The default is AUTO, which automatically tries to detect whether the background is dark. Capability of auto-detection depends on the user interface.

TYPE: DarkBackground.Literals DEFAULT: 'auto'

bg

If False, uses transparent background for the output. In the case of terminal output, the background color will be the current background color of the terminal. For HTML output, the background color will be automatically set to pure black or pure white, depending on the luminosity of the foreground color.

TYPE: bool DEFAULT: False

fonts

Font families to use in HTML output, in order of preference (empty tuple for browser default).

TYPE: Tuple[str, ...] DEFAULT: ('Menlo', 'DejaVu Sans Mono', 'Consolas', 'Courier New', 'monospace')

font_size

Font size in pixels for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 14

font_weight

Font weight for HTML output (None for browser default).

TYPE: NonNegativeInt | None DEFAULT: 400

line_height

Line height multiplier for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 1.25

h_overflow

How to handle text that exceeds the width.

TYPE: HorizontalOverflowMode.Literals DEFAULT: 'ellipsis'

v_overflow

How to handle text that exceeds the height.

TYPE: VerticalOverflowMode.Literals DEFAULT: 'ellipsis_bottom'

panel

Visual design of the panel used as container for the output. Only TABLE is currently supported, which displays the output in a table-like grid.

TYPE: PanelDesign.Literals DEFAULT: 'table'

title_at_top

Whether panel titles will be displayed over the panel content (True) or below the content (False)

TYPE: bool DEFAULT: True

max_title_height

Maximum height of the panel title. If AUTO, the height is determined by the content of the title, up to a maximum of two lines. If ZERO, the title is not displayed at all. If ONE or TWO, the title is displayed with a fixed height of max one or two lines, respectively.

TYPE: MaxTitleHeight.Literals DEFAULT: -1

min_panel_width

Minimum width in characters per panel.

TYPE: NonNegativeInt DEFAULT: 3

min_crop_width

Minimum cropping width in characters for panels in cases where more than one panel are to be displayed. This is for instance used to calculate the number of models to display in a Dataset peek(). Only applied if use_min_crop_width is set to True. min_crop_width must be equal to or larger than min_panel_width.

TYPE: NonNegativeInt DEFAULT: 33

use_min_crop_width

Whether the min_crop_width value should be considered in cases where more than one panel are to be displayed, potentially reducing the number of displayed panels.

TYPE: bool DEFAULT: False

max_panels_hor

Maximum number of panels to display horizontally side-by-side at the top level. This value also acts as a ceiling for nested panels; nested panels cannot exceed this limit even if the constant MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED is set to a higher value. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 9

max_nesting_depth

Maximum levels of nested panels to display. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 3

justify

Justification mode for the panel if inside a layout panel. This is only used for the panel content.

TYPE: Justify.Literals DEFAULT: 'left'

RETURNS DESCRIPTION
Element | None

If the UI type is Jupyter running in browser, the method returns a ReactivelyResizingHtml element which is a Jupyter widget to display HTML output in the browser. Otherwise, the method returns None.

Note

Any default argument value is overridden by the corresponding value in the relevant subsection of the UserInterfaceConfig.

Source code in src/omnipy/data/_mixins/display.py
def full(self, **kwargs) -> 'Element | None':
    # %% Original docstring (managed by expand_docstr_macros.py) %%
    # {{FULL_SUMMARY}}
    #
    # {{FULL_DESCRIPTION}}
    #
    # {{DISPLAY_METHOD_ARGS}}
    #
    # {{DISPLAY_METHOD_RETURNS}}
    #
    # {{DISPLAY_METHOD_NOTE}}
    #
    #
    """Display the content of the Model or Dataset in full height.

    `full()` is a shorthand for `peek(height=None)` for both
    models and datasets. Both full-height views are automatically
    limited in width by the available display dimensions.

    Args:
        width (NonNegativeInt | None):
            Width in characters of the output area (None for
            auto-detect based on available display dimensions).
        height (NonNegativeInt | None):
            Height in lines of the output area (None for
            auto-detect based on available display dimensions).
        tab (NonNegativeInt):
            Number of spaces to use for each tab.
        indent (NonNegativeInt):
            Number of spaces to use for each indentation level.
        printer (PrettyPrinterLib.Literals):
            Library to use for pretty printing.
        syntax (SyntaxLanguageSpec.Literals | str):
            Syntax language for code highlighting. Supported
            lexers are defined in SyntaxLanguageSpec. For
            non-supported styles, the user can specify a string
            with the Pygments lexer name. For this to work, the
            lexer must be registered in the Pygments library.
        freedom (float | None):
            Parameter that controls the level of freedom for
            formatted text to follow the geometry of the frame
            size (=total available area) in a proportional manner.
            If the proportional freedom is 0 (the lowest), then
            the output area must not in any case be proportionally
            wider that the frame (i.e. a 16/9 frame will only
            produce output that is 16/9 or narrower). Larger
            values of proportional freedom allow the output to be
            proportionally wider than the total available frame,
            to a degree that relates to the size difference
            between the frame and the content (larger difference
            gives more freedom). The default value of 2.5 is a
            good compromise between readability/aesthetics and
            good use of the screen estate. If None, the freedom is
            unlimited (i.e. proportionality is not taken into
            account at all).
        debug (bool):
            When True, enables additional debugging information in
            the output, such as the hierarchy of the Model
            objects. Currently, only Python pretty printers support
            debug=True. Hence, enabling debug mode will
            automatically set the printer to the default Python
            pretty printer if the `printer` config value is not
            already set.
        ui (UserInterfaceType.Literals):
            Type of user interface for which the output should
            being prepared. The user interface describes the
            technical solutions available for interacting with the
            user, encompassing the support available for
            displaying output as well as how the user interacts
            with the library (including the type of interactive
            interpreter used, if any).
        system (ColorSystem.Literals):
            Color system to use for terminal output. The default
            is `AUTO`, which automatically detects the color
            system based on particular environment variables. If
            color capabilities are not detected, the output will
            be in black and white. If the color system of a modern
            consoles/terminal is not auto-detected (which is the
            case for e.g. the PyCharm console), the user might
            want to set the color system manually to ANSI_RGB to
            force color output.
        style (AllColorStyles.Literals | str):
            Color style/theme for syntax highlighting and other
            display elements. Supported styles are defined in
            AllColorStyles. For non-supported styles, the user can
            specify a string with the Pygments style name. For this to
            work, the style must be registered in the Pygments
            library. If style is `AUTO` or any of the other
            RecommendedColorStyles, the style is automatically
            selected from the RecommendedColorStyles based on the
            detected user interface, the color system, and whether the
            background is dark or not.
        dark (DarkBackground.Literals):
            Whether the background color of the output is dark.
            This is used to determine the appropriate color scheme
            for syntax highlighting. The default is AUTO, which
            automatically tries to detect whether the background
            is dark. Capability of auto-detection depends on the
            user interface.
        bg (bool):
            If False, uses transparent background for the output.
            In the case of terminal output, the background color
            will be the current background color of the terminal.
            For HTML output, the background color will be
            automatically set to pure black or pure white,
            depending on the luminosity of the foreground color.
        fonts (Tuple[str, ...]):
            Font families to use in HTML output, in order of
            preference (empty tuple for browser default).
        font_size (NonNegativeFloat | None):
            Font size in pixels for HTML output (None for browser
            default).
        font_weight (NonNegativeInt | None):
            Font weight for HTML output (None for browser
            default).
        line_height (NonNegativeFloat | None):
            Line height multiplier for HTML output (None for
            browser default).
        h_overflow (HorizontalOverflowMode.Literals):
            How to handle text that exceeds the width.
        v_overflow (VerticalOverflowMode.Literals):
            How to handle text that exceeds the height.
        panel (PanelDesign.Literals):
            Visual design of the panel used as container for the
            output. Only `TABLE` is currently supported, which
            displays the output in a table-like grid.
        title_at_top (bool):
            Whether panel titles will be displayed over the panel
            content (True) or below the content (False)
        max_title_height (MaxTitleHeight.Literals):
            Maximum height of the panel title. If `AUTO`, the
            height is determined by the content of the title, up
            to a maximum of two lines. If `ZERO`, the title is not
            displayed at all. If `ONE` or `TWO`, the title is
            displayed with a fixed height of max one or two lines,
            respectively.
        min_panel_width (NonNegativeInt):
            Minimum width in characters per panel.
        min_crop_width (NonNegativeInt):
            Minimum cropping width in characters for panels in
            cases where more than one panel are to be displayed.
            This is for instance used to calculate the number of
            models to display in a Dataset peek(). Only applied if
            `use_min_crop_width` is set to `True`.
            `min_crop_width` must be equal to or larger than
            `min_panel_width`.
        use_min_crop_width (bool):
            Whether the `min_crop_width` value should be
            considered in cases where more than one panel are to
            be displayed, potentially reducing the number of
            displayed panels.
        max_panels_hor (NonNegativeInt | None):
            Maximum number of panels to display horizontally
            side-by-side at the top level. This value also acts as
            a ceiling for nested panels; nested panels cannot
            exceed this limit even if the constant
            `MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED` is set to a
            higher value. If None, there is no limit.
        max_nesting_depth (NonNegativeInt | None):
            Maximum levels of nested panels to display. If None,
            there is no limit.
        justify (Justify.Literals):
            Justification mode for the panel if inside a layout
            panel. This is only used for the panel content.

    Returns:
        If the UI type is Jupyter running in browser, the
        method returns a ReactivelyResizingHtml element which
        is a Jupyter widget to display HTML output in the
        browser. Otherwise, the method returns None.

    Note:
        Any default argument value is overridden by the
        corresponding value in the relevant subsection of the
        UserInterfaceConfig.

    """
    return self._display_according_to_ui_type(
        ui_type=self._extract_ui_type(**kwargs),
        return_output_if_str=False,
        output_method=self._full,
        **kwargs)

full_type cached classmethod

full_type() -> type[_RootT]

Return the model's full declared root type including type arguments.

RETURNS DESCRIPTION
type[_RootT]

The complete concrete type bound to this model.

Source code in src/omnipy/data/model.py
@classmethod
@functools.cache
def full_type(cls) -> type[_RootT]:
    """Return the model's full declared root type including type arguments.

    Returns:
        The complete concrete type bound to this model.
    """
    return cast(type[_RootT], cls.outer_type(with_args=True))

get_orig_model classmethod

get_orig_model() -> type[_RootT] | UndefinedType

Return the original declared model type before internal normalization.

RETURNS DESCRIPTION
type[_RootT] | UndefinedType

The original type expression supplied for this model specialization, or :data:Undefined when no original type has been recorded.

Source code in src/omnipy/data/model.py
@classmethod
def get_orig_model(cls) -> type[_RootT] | UndefinedType:
    """Return the original declared model type before internal normalization.

    Returns:
        The original type expression supplied for this model specialization,
        or :data:`Undefined` when no original type has been recorded.
    """
    if cls.__fields__[ROOT_KEY].field_info and cls.__fields__[ROOT_KEY].field_info.extra:
        return cls.__fields__[ROOT_KEY].field_info.extra.get('orig_model', Undefined)
    return Undefined

has_snapshot

has_snapshot() -> bool

Check whether this model currently has a stored snapshot.

RETURNS DESCRIPTION
bool

True if interactive snapshot state exists for this model.

Source code in src/omnipy/data/model.py
def has_snapshot(self) -> bool:
    """Check whether this model currently has a stored snapshot.

    Returns:
        ``True`` if interactive snapshot state exists for this model.
    """
    return self in self.snapshot_holder

inner_type cached classmethod

inner_type(with_args: bool = False) -> TypeForm

Return the inner validated root type for this model class.

PARAMETER DESCRIPTION
with_args

When True, preserve type arguments such as list[int].

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
TypeForm

The inner root type used after pydantic normalization.

Source code in src/omnipy/data/model.py
@classmethod
@functools.cache
def inner_type(cls, with_args: bool = False) -> TypeForm:
    """Return the inner validated root type for this model class.

    Args:
        with_args: When ``True``, preserve type arguments such as ``list[int]``.

    Returns:
        The inner root type used after pydantic normalization.
    """
    return cls._get_root_type(outer=False, with_args=with_args)

is_nested_type cached classmethod

is_nested_type() -> bool

Check whether this model wraps a nested or transformed root type.

RETURNS DESCRIPTION
bool

True when the inner validated type differs from the declared outer type.

Source code in src/omnipy/data/model.py
@classmethod
@functools.cache
def is_nested_type(cls) -> bool:
    """Check whether this model wraps a nested or transformed root type.

    Returns:
        ``True`` when the inner validated type differs from the declared
        outer type.
    """
    return not cls.inner_type(with_args=True) == cls.outer_type(with_args=True)

json

json(
    *,
    width: pyd.NonNegativeInt | None = None,
    height: pyd.NonNegativeInt | None = None,
    tab: pyd.NonNegativeInt = 4,
    indent: pyd.NonNegativeInt = 2,
    printer: PrettyPrinterLib.Literals = "auto",
    syntax: SyntaxLanguageSpec.Literals | str = "auto",
    freedom: pyd.NonNegativeFloat | None = 2.5,
    debug: bool = False,
    ui: UserInterfaceType.Literals = "auto",
    system: DisplayColorSystem.Literals = "auto",
    style: AllColorStyles.Literals | str = "auto",
    dark: typing.Literal["auto", True, False] = "auto",
    bg: bool = False,
    fonts: tuple[str, ...] = ("Menlo", "DejaVu Sans Mono", "Consolas", "Courier New", "monospace"),
    font_size: pyd.NonNegativeFloat | None = 14,
    font_weight: pyd.NonNegativeInt | None = 400,
    line_height: pyd.NonNegativeFloat | None = 1.25,
    h_overflow: HorizontalOverflowMode.Literals = "ellipsis",
    v_overflow: VerticalOverflowMode.Literals = "ellipsis_bottom",
    panel: PanelDesign.Literals = "table",
    title_at_top: bool = True,
    max_title_height: MaxTitleHeight.Literals = -1,
    min_panel_width: pyd.NonNegativeInt = 3,
    min_crop_width: pyd.NonNegativeInt = 33,
    use_min_crop_width: bool = False,
    max_panels_hor: pyd.NonNegativeInt | None = 9,
    max_nesting_depth: pyd.NonNegativeInt | None = 3,
    justify: Justify.Literals = "left",
) -> Element | None

Preview the data content of the Model or Dataset as JSON.

In contrast to e.g. peek(), json() displays the "data content" of the Model or Dataset, i.e. the content as plain Python objects, potentially converted from the internal data structure. This plain data is formatted in JSON (for compactness). Hence json() represents a the basic compatibility layer of all Omnipy Model or Dataset objects. The view is automatically limited by the available display dimensions.

PARAMETER DESCRIPTION
width

Width in characters of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

height

Height in lines of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

tab

Number of spaces to use for each tab.

TYPE: NonNegativeInt DEFAULT: 4

indent

Number of spaces to use for each indentation level.

TYPE: NonNegativeInt DEFAULT: 2

printer

Library to use for pretty printing.

TYPE: PrettyPrinterLib.Literals DEFAULT: 'auto'

syntax

Syntax language for code highlighting. Supported lexers are defined in SyntaxLanguageSpec. For non-supported styles, the user can specify a string with the Pygments lexer name. For this to work, the lexer must be registered in the Pygments library.

TYPE: SyntaxLanguageSpec.Literals | str DEFAULT: 'auto'

freedom

Parameter that controls the level of freedom for formatted text to follow the geometry of the frame size (=total available area) in a proportional manner. If the proportional freedom is 0 (the lowest), then the output area must not in any case be proportionally wider that the frame (i.e. a 16/9 frame will only produce output that is 16/9 or narrower). Larger values of proportional freedom allow the output to be proportionally wider than the total available frame, to a degree that relates to the size difference between the frame and the content (larger difference gives more freedom). The default value of 2.5 is a good compromise between readability/aesthetics and good use of the screen estate. If None, the freedom is unlimited (i.e. proportionality is not taken into account at all).

TYPE: float | None DEFAULT: 2.5

debug

When True, enables additional debugging information in the output, such as the hierarchy of the Model objects. Currently, only Python pretty printers support debug=True. Hence, enabling debug mode will automatically set the printer to the default Python pretty printer if the printer config value is not already set.

TYPE: bool DEFAULT: False

ui

Type of user interface for which the output should being prepared. The user interface describes the technical solutions available for interacting with the user, encompassing the support available for displaying output as well as how the user interacts with the library (including the type of interactive interpreter used, if any).

TYPE: UserInterfaceType.Literals DEFAULT: 'auto'

system

Color system to use for terminal output. The default is AUTO, which automatically detects the color system based on particular environment variables. If color capabilities are not detected, the output will be in black and white. If the color system of a modern consoles/terminal is not auto-detected (which is the case for e.g. the PyCharm console), the user might want to set the color system manually to ANSI_RGB to force color output.

TYPE: ColorSystem.Literals DEFAULT: 'auto'

style

Color style/theme for syntax highlighting and other display elements. Supported styles are defined in AllColorStyles. For non-supported styles, the user can specify a string with the Pygments style name. For this to work, the style must be registered in the Pygments library. If style is AUTO or any of the other RecommendedColorStyles, the style is automatically selected from the RecommendedColorStyles based on the detected user interface, the color system, and whether the background is dark or not.

TYPE: AllColorStyles.Literals | str DEFAULT: 'auto'

dark

Whether the background color of the output is dark. This is used to determine the appropriate color scheme for syntax highlighting. The default is AUTO, which automatically tries to detect whether the background is dark. Capability of auto-detection depends on the user interface.

TYPE: DarkBackground.Literals DEFAULT: 'auto'

bg

If False, uses transparent background for the output. In the case of terminal output, the background color will be the current background color of the terminal. For HTML output, the background color will be automatically set to pure black or pure white, depending on the luminosity of the foreground color.

TYPE: bool DEFAULT: False

fonts

Font families to use in HTML output, in order of preference (empty tuple for browser default).

TYPE: Tuple[str, ...] DEFAULT: ('Menlo', 'DejaVu Sans Mono', 'Consolas', 'Courier New', 'monospace')

font_size

Font size in pixels for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 14

font_weight

Font weight for HTML output (None for browser default).

TYPE: NonNegativeInt | None DEFAULT: 400

line_height

Line height multiplier for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 1.25

h_overflow

How to handle text that exceeds the width.

TYPE: HorizontalOverflowMode.Literals DEFAULT: 'ellipsis'

v_overflow

How to handle text that exceeds the height.

TYPE: VerticalOverflowMode.Literals DEFAULT: 'ellipsis_bottom'

panel

Visual design of the panel used as container for the output. Only TABLE is currently supported, which displays the output in a table-like grid.

TYPE: PanelDesign.Literals DEFAULT: 'table'

title_at_top

Whether panel titles will be displayed over the panel content (True) or below the content (False)

TYPE: bool DEFAULT: True

max_title_height

Maximum height of the panel title. If AUTO, the height is determined by the content of the title, up to a maximum of two lines. If ZERO, the title is not displayed at all. If ONE or TWO, the title is displayed with a fixed height of max one or two lines, respectively.

TYPE: MaxTitleHeight.Literals DEFAULT: -1

min_panel_width

Minimum width in characters per panel.

TYPE: NonNegativeInt DEFAULT: 3

min_crop_width

Minimum cropping width in characters for panels in cases where more than one panel are to be displayed. This is for instance used to calculate the number of models to display in a Dataset peek(). Only applied if use_min_crop_width is set to True. min_crop_width must be equal to or larger than min_panel_width.

TYPE: NonNegativeInt DEFAULT: 33

use_min_crop_width

Whether the min_crop_width value should be considered in cases where more than one panel are to be displayed, potentially reducing the number of displayed panels.

TYPE: bool DEFAULT: False

max_panels_hor

Maximum number of panels to display horizontally side-by-side at the top level. This value also acts as a ceiling for nested panels; nested panels cannot exceed this limit even if the constant MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED is set to a higher value. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 9

max_nesting_depth

Maximum levels of nested panels to display. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 3

justify

Justification mode for the panel if inside a layout panel. This is only used for the panel content.

TYPE: Justify.Literals DEFAULT: 'left'

RETURNS DESCRIPTION
Element | None

If the UI type is Jupyter running in browser, the method returns a ReactivelyResizingHtml element which is a Jupyter widget to display HTML output in the browser. Otherwise, the method returns None.

Note

Any default argument value is overridden by the corresponding value in the relevant subsection of the UserInterfaceConfig.

Source code in src/omnipy/data/_mixins/display.py
def json(self, **kwargs) -> None:
    # %% Original docstring (managed by expand_docstr_macros.py) %%
    # {{JSON_SUMMARY}}
    #
    # {{JSON_DESCRIPTION}}
    #
    # {{DISPLAY_METHOD_ARGS}}
    #
    # {{DISPLAY_METHOD_RETURNS}}
    #
    # {{DISPLAY_METHOD_NOTE}}
    #
    """Preview the data content of the Model or Dataset as JSON.

    In contrast to e.g. `peek()`, `json()` displays the "data
    content" of the Model or Dataset, i.e. the content as plain
    Python objects, potentially converted from the internal data
    structure. This plain data is formatted in JSON (for
    compactness). Hence `json()` represents a the basic
    compatibility layer of all Omnipy Model or Dataset objects.
    The view is automatically limited by the available display
    dimensions.

    Args:
        width (NonNegativeInt | None):
            Width in characters of the output area (None for
            auto-detect based on available display dimensions).
        height (NonNegativeInt | None):
            Height in lines of the output area (None for
            auto-detect based on available display dimensions).
        tab (NonNegativeInt):
            Number of spaces to use for each tab.
        indent (NonNegativeInt):
            Number of spaces to use for each indentation level.
        printer (PrettyPrinterLib.Literals):
            Library to use for pretty printing.
        syntax (SyntaxLanguageSpec.Literals | str):
            Syntax language for code highlighting. Supported
            lexers are defined in SyntaxLanguageSpec. For
            non-supported styles, the user can specify a string
            with the Pygments lexer name. For this to work, the
            lexer must be registered in the Pygments library.
        freedom (float | None):
            Parameter that controls the level of freedom for
            formatted text to follow the geometry of the frame
            size (=total available area) in a proportional manner.
            If the proportional freedom is 0 (the lowest), then
            the output area must not in any case be proportionally
            wider that the frame (i.e. a 16/9 frame will only
            produce output that is 16/9 or narrower). Larger
            values of proportional freedom allow the output to be
            proportionally wider than the total available frame,
            to a degree that relates to the size difference
            between the frame and the content (larger difference
            gives more freedom). The default value of 2.5 is a
            good compromise between readability/aesthetics and
            good use of the screen estate. If None, the freedom is
            unlimited (i.e. proportionality is not taken into
            account at all).
        debug (bool):
            When True, enables additional debugging information in
            the output, such as the hierarchy of the Model
            objects. Currently, only Python pretty printers support
            debug=True. Hence, enabling debug mode will
            automatically set the printer to the default Python
            pretty printer if the `printer` config value is not
            already set.
        ui (UserInterfaceType.Literals):
            Type of user interface for which the output should
            being prepared. The user interface describes the
            technical solutions available for interacting with the
            user, encompassing the support available for
            displaying output as well as how the user interacts
            with the library (including the type of interactive
            interpreter used, if any).
        system (ColorSystem.Literals):
            Color system to use for terminal output. The default
            is `AUTO`, which automatically detects the color
            system based on particular environment variables. If
            color capabilities are not detected, the output will
            be in black and white. If the color system of a modern
            consoles/terminal is not auto-detected (which is the
            case for e.g. the PyCharm console), the user might
            want to set the color system manually to ANSI_RGB to
            force color output.
        style (AllColorStyles.Literals | str):
            Color style/theme for syntax highlighting and other
            display elements. Supported styles are defined in
            AllColorStyles. For non-supported styles, the user can
            specify a string with the Pygments style name. For this to
            work, the style must be registered in the Pygments
            library. If style is `AUTO` or any of the other
            RecommendedColorStyles, the style is automatically
            selected from the RecommendedColorStyles based on the
            detected user interface, the color system, and whether the
            background is dark or not.
        dark (DarkBackground.Literals):
            Whether the background color of the output is dark.
            This is used to determine the appropriate color scheme
            for syntax highlighting. The default is AUTO, which
            automatically tries to detect whether the background
            is dark. Capability of auto-detection depends on the
            user interface.
        bg (bool):
            If False, uses transparent background for the output.
            In the case of terminal output, the background color
            will be the current background color of the terminal.
            For HTML output, the background color will be
            automatically set to pure black or pure white,
            depending on the luminosity of the foreground color.
        fonts (Tuple[str, ...]):
            Font families to use in HTML output, in order of
            preference (empty tuple for browser default).
        font_size (NonNegativeFloat | None):
            Font size in pixels for HTML output (None for browser
            default).
        font_weight (NonNegativeInt | None):
            Font weight for HTML output (None for browser
            default).
        line_height (NonNegativeFloat | None):
            Line height multiplier for HTML output (None for
            browser default).
        h_overflow (HorizontalOverflowMode.Literals):
            How to handle text that exceeds the width.
        v_overflow (VerticalOverflowMode.Literals):
            How to handle text that exceeds the height.
        panel (PanelDesign.Literals):
            Visual design of the panel used as container for the
            output. Only `TABLE` is currently supported, which
            displays the output in a table-like grid.
        title_at_top (bool):
            Whether panel titles will be displayed over the panel
            content (True) or below the content (False)
        max_title_height (MaxTitleHeight.Literals):
            Maximum height of the panel title. If `AUTO`, the
            height is determined by the content of the title, up
            to a maximum of two lines. If `ZERO`, the title is not
            displayed at all. If `ONE` or `TWO`, the title is
            displayed with a fixed height of max one or two lines,
            respectively.
        min_panel_width (NonNegativeInt):
            Minimum width in characters per panel.
        min_crop_width (NonNegativeInt):
            Minimum cropping width in characters for panels in
            cases where more than one panel are to be displayed.
            This is for instance used to calculate the number of
            models to display in a Dataset peek(). Only applied if
            `use_min_crop_width` is set to `True`.
            `min_crop_width` must be equal to or larger than
            `min_panel_width`.
        use_min_crop_width (bool):
            Whether the `min_crop_width` value should be
            considered in cases where more than one panel are to
            be displayed, potentially reducing the number of
            displayed panels.
        max_panels_hor (NonNegativeInt | None):
            Maximum number of panels to display horizontally
            side-by-side at the top level. This value also acts as
            a ceiling for nested panels; nested panels cannot
            exceed this limit even if the constant
            `MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED` is set to a
            higher value. If None, there is no limit.
        max_nesting_depth (NonNegativeInt | None):
            Maximum levels of nested panels to display. If None,
            there is no limit.
        justify (Justify.Literals):
            Justification mode for the panel if inside a layout
            panel. This is only used for the panel content.

    Returns:
        If the UI type is Jupyter running in browser, the
        method returns a ReactivelyResizingHtml element which
        is a Jupyter widget to display HTML output in the
        browser. Otherwise, the method returns None.

    Note:
        Any default argument value is overridden by the
        corresponding value in the relevant subsection of the
        UserInterfaceConfig.
    """
    return self._display_according_to_ui_type(
        ui_type=self._extract_ui_type(**kwargs),
        return_output_if_str=False,
        output_method=self._json,
        **kwargs)

outer_type cached classmethod

outer_type(with_args: bool = False) -> TypeForm

Return the declared outer root type for this model class.

PARAMETER DESCRIPTION
with_args

When True, preserve type arguments such as list[int].

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
TypeForm

The outer root type exposed by the model.

Source code in src/omnipy/data/model.py
@classmethod
@functools.cache
def outer_type(cls, with_args: bool = False) -> TypeForm:
    """Return the declared outer root type for this model class.

    Args:
        with_args: When ``True``, preserve type arguments such as ``list[int]``.

    Returns:
        The outer root type exposed by the model.
    """
    return cls._get_root_type(outer=True, with_args=with_args)

peek

peek(
    *,
    width: pyd.NonNegativeInt | None = None,
    height: pyd.NonNegativeInt | None = None,
    tab: pyd.NonNegativeInt = 4,
    indent: pyd.NonNegativeInt = 2,
    printer: PrettyPrinterLib.Literals = "auto",
    syntax: SyntaxLanguageSpec.Literals | str = "auto",
    freedom: pyd.NonNegativeFloat | None = 2.5,
    debug: bool = False,
    ui: UserInterfaceType.Literals = "auto",
    system: DisplayColorSystem.Literals = "auto",
    style: AllColorStyles.Literals | str = "auto",
    dark: typing.Literal["auto", True, False] = "auto",
    bg: bool = False,
    fonts: tuple[str, ...] = ("Menlo", "DejaVu Sans Mono", "Consolas", "Courier New", "monospace"),
    font_size: pyd.NonNegativeFloat | None = 14,
    font_weight: pyd.NonNegativeInt | None = 400,
    line_height: pyd.NonNegativeFloat | None = 1.25,
    h_overflow: HorizontalOverflowMode.Literals = "ellipsis",
    v_overflow: VerticalOverflowMode.Literals = "ellipsis_bottom",
    panel: PanelDesign.Literals = "table",
    title_at_top: bool = True,
    max_title_height: MaxTitleHeight.Literals = -1,
    min_panel_width: pyd.NonNegativeInt = 3,
    min_crop_width: pyd.NonNegativeInt = 33,
    use_min_crop_width: bool = False,
    max_panels_hor: pyd.NonNegativeInt | None = 9,
    max_nesting_depth: pyd.NonNegativeInt | None = 3,
    justify: Justify.Literals = "left",
) -> Element | None

Display a preview of the Model or Dataset content.

For Model instances, peek() displays a preview of the model's content. For Dataset instances, peek() displays a side-by-side view of each model contained in the dataset. Both views are automatically limited by the available display dimensions.

PARAMETER DESCRIPTION
width

Width in characters of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

height

Height in lines of the output area (None for auto-detect based on available display dimensions).

TYPE: NonNegativeInt | None DEFAULT: None

tab

Number of spaces to use for each tab.

TYPE: NonNegativeInt DEFAULT: 4

indent

Number of spaces to use for each indentation level.

TYPE: NonNegativeInt DEFAULT: 2

printer

Library to use for pretty printing.

TYPE: PrettyPrinterLib.Literals DEFAULT: 'auto'

syntax

Syntax language for code highlighting. Supported lexers are defined in SyntaxLanguageSpec. For non-supported styles, the user can specify a string with the Pygments lexer name. For this to work, the lexer must be registered in the Pygments library.

TYPE: SyntaxLanguageSpec.Literals | str DEFAULT: 'auto'

freedom

Parameter that controls the level of freedom for formatted text to follow the geometry of the frame size (=total available area) in a proportional manner. If the proportional freedom is 0 (the lowest), then the output area must not in any case be proportionally wider that the frame (i.e. a 16/9 frame will only produce output that is 16/9 or narrower). Larger values of proportional freedom allow the output to be proportionally wider than the total available frame, to a degree that relates to the size difference between the frame and the content (larger difference gives more freedom). The default value of 2.5 is a good compromise between readability/aesthetics and good use of the screen estate. If None, the freedom is unlimited (i.e. proportionality is not taken into account at all).

TYPE: float | None DEFAULT: 2.5

debug

When True, enables additional debugging information in the output, such as the hierarchy of the Model objects. Currently, only Python pretty printers support debug=True. Hence, enabling debug mode will automatically set the printer to the default Python pretty printer if the printer config value is not already set.

TYPE: bool DEFAULT: False

ui

Type of user interface for which the output should being prepared. The user interface describes the technical solutions available for interacting with the user, encompassing the support available for displaying output as well as how the user interacts with the library (including the type of interactive interpreter used, if any).

TYPE: UserInterfaceType.Literals DEFAULT: 'auto'

system

Color system to use for terminal output. The default is AUTO, which automatically detects the color system based on particular environment variables. If color capabilities are not detected, the output will be in black and white. If the color system of a modern consoles/terminal is not auto-detected (which is the case for e.g. the PyCharm console), the user might want to set the color system manually to ANSI_RGB to force color output.

TYPE: ColorSystem.Literals DEFAULT: 'auto'

style

Color style/theme for syntax highlighting and other display elements. Supported styles are defined in AllColorStyles. For non-supported styles, the user can specify a string with the Pygments style name. For this to work, the style must be registered in the Pygments library. If style is AUTO or any of the other RecommendedColorStyles, the style is automatically selected from the RecommendedColorStyles based on the detected user interface, the color system, and whether the background is dark or not.

TYPE: AllColorStyles.Literals | str DEFAULT: 'auto'

dark

Whether the background color of the output is dark. This is used to determine the appropriate color scheme for syntax highlighting. The default is AUTO, which automatically tries to detect whether the background is dark. Capability of auto-detection depends on the user interface.

TYPE: DarkBackground.Literals DEFAULT: 'auto'

bg

If False, uses transparent background for the output. In the case of terminal output, the background color will be the current background color of the terminal. For HTML output, the background color will be automatically set to pure black or pure white, depending on the luminosity of the foreground color.

TYPE: bool DEFAULT: False

fonts

Font families to use in HTML output, in order of preference (empty tuple for browser default).

TYPE: Tuple[str, ...] DEFAULT: ('Menlo', 'DejaVu Sans Mono', 'Consolas', 'Courier New', 'monospace')

font_size

Font size in pixels for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 14

font_weight

Font weight for HTML output (None for browser default).

TYPE: NonNegativeInt | None DEFAULT: 400

line_height

Line height multiplier for HTML output (None for browser default).

TYPE: NonNegativeFloat | None DEFAULT: 1.25

h_overflow

How to handle text that exceeds the width.

TYPE: HorizontalOverflowMode.Literals DEFAULT: 'ellipsis'

v_overflow

How to handle text that exceeds the height.

TYPE: VerticalOverflowMode.Literals DEFAULT: 'ellipsis_bottom'

panel

Visual design of the panel used as container for the output. Only TABLE is currently supported, which displays the output in a table-like grid.

TYPE: PanelDesign.Literals DEFAULT: 'table'

title_at_top

Whether panel titles will be displayed over the panel content (True) or below the content (False)

TYPE: bool DEFAULT: True

max_title_height

Maximum height of the panel title. If AUTO, the height is determined by the content of the title, up to a maximum of two lines. If ZERO, the title is not displayed at all. If ONE or TWO, the title is displayed with a fixed height of max one or two lines, respectively.

TYPE: MaxTitleHeight.Literals DEFAULT: -1

min_panel_width

Minimum width in characters per panel.

TYPE: NonNegativeInt DEFAULT: 3

min_crop_width

Minimum cropping width in characters for panels in cases where more than one panel are to be displayed. This is for instance used to calculate the number of models to display in a Dataset peek(). Only applied if use_min_crop_width is set to True. min_crop_width must be equal to or larger than min_panel_width.

TYPE: NonNegativeInt DEFAULT: 33

use_min_crop_width

Whether the min_crop_width value should be considered in cases where more than one panel are to be displayed, potentially reducing the number of displayed panels.

TYPE: bool DEFAULT: False

max_panels_hor

Maximum number of panels to display horizontally side-by-side at the top level. This value also acts as a ceiling for nested panels; nested panels cannot exceed this limit even if the constant MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED is set to a higher value. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 9

max_nesting_depth

Maximum levels of nested panels to display. If None, there is no limit.

TYPE: NonNegativeInt | None DEFAULT: 3

justify

Justification mode for the panel if inside a layout panel. This is only used for the panel content.

TYPE: Justify.Literals DEFAULT: 'left'

RETURNS DESCRIPTION
Element | None

If the UI type is Jupyter running in browser, the method returns a ReactivelyResizingHtml element which is a Jupyter widget to display HTML output in the browser. Otherwise, the method returns None.

Note

Any default argument value is overridden by the corresponding value in the relevant subsection of the UserInterfaceConfig.

Source code in src/omnipy/data/_mixins/display.py
def peek(self, **kwargs) -> 'Element | None':
    # %% Original docstring (managed by expand_docstr_macros.py) %%
    # {{PEEK_SUMMARY}}
    #
    # {{PEEK_DESCRIPTION}}
    #
    # {{DISPLAY_METHOD_ARGS}}
    #
    # {{DISPLAY_METHOD_RETURNS}}
    #
    # {{DISPLAY_METHOD_NOTE}}
    #
    """Display a preview of the Model or Dataset content.

    For Model instances, `peek()` displays a preview of the
    model's content. For Dataset instances, `peek()` displays a
    side-by-side view of each model contained in the dataset. Both
    views are automatically limited by the available display
    dimensions.

    Args:
        width (NonNegativeInt | None):
            Width in characters of the output area (None for
            auto-detect based on available display dimensions).
        height (NonNegativeInt | None):
            Height in lines of the output area (None for
            auto-detect based on available display dimensions).
        tab (NonNegativeInt):
            Number of spaces to use for each tab.
        indent (NonNegativeInt):
            Number of spaces to use for each indentation level.
        printer (PrettyPrinterLib.Literals):
            Library to use for pretty printing.
        syntax (SyntaxLanguageSpec.Literals | str):
            Syntax language for code highlighting. Supported
            lexers are defined in SyntaxLanguageSpec. For
            non-supported styles, the user can specify a string
            with the Pygments lexer name. For this to work, the
            lexer must be registered in the Pygments library.
        freedom (float | None):
            Parameter that controls the level of freedom for
            formatted text to follow the geometry of the frame
            size (=total available area) in a proportional manner.
            If the proportional freedom is 0 (the lowest), then
            the output area must not in any case be proportionally
            wider that the frame (i.e. a 16/9 frame will only
            produce output that is 16/9 or narrower). Larger
            values of proportional freedom allow the output to be
            proportionally wider than the total available frame,
            to a degree that relates to the size difference
            between the frame and the content (larger difference
            gives more freedom). The default value of 2.5 is a
            good compromise between readability/aesthetics and
            good use of the screen estate. If None, the freedom is
            unlimited (i.e. proportionality is not taken into
            account at all).
        debug (bool):
            When True, enables additional debugging information in
            the output, such as the hierarchy of the Model
            objects. Currently, only Python pretty printers support
            debug=True. Hence, enabling debug mode will
            automatically set the printer to the default Python
            pretty printer if the `printer` config value is not
            already set.
        ui (UserInterfaceType.Literals):
            Type of user interface for which the output should
            being prepared. The user interface describes the
            technical solutions available for interacting with the
            user, encompassing the support available for
            displaying output as well as how the user interacts
            with the library (including the type of interactive
            interpreter used, if any).
        system (ColorSystem.Literals):
            Color system to use for terminal output. The default
            is `AUTO`, which automatically detects the color
            system based on particular environment variables. If
            color capabilities are not detected, the output will
            be in black and white. If the color system of a modern
            consoles/terminal is not auto-detected (which is the
            case for e.g. the PyCharm console), the user might
            want to set the color system manually to ANSI_RGB to
            force color output.
        style (AllColorStyles.Literals | str):
            Color style/theme for syntax highlighting and other
            display elements. Supported styles are defined in
            AllColorStyles. For non-supported styles, the user can
            specify a string with the Pygments style name. For this to
            work, the style must be registered in the Pygments
            library. If style is `AUTO` or any of the other
            RecommendedColorStyles, the style is automatically
            selected from the RecommendedColorStyles based on the
            detected user interface, the color system, and whether the
            background is dark or not.
        dark (DarkBackground.Literals):
            Whether the background color of the output is dark.
            This is used to determine the appropriate color scheme
            for syntax highlighting. The default is AUTO, which
            automatically tries to detect whether the background
            is dark. Capability of auto-detection depends on the
            user interface.
        bg (bool):
            If False, uses transparent background for the output.
            In the case of terminal output, the background color
            will be the current background color of the terminal.
            For HTML output, the background color will be
            automatically set to pure black or pure white,
            depending on the luminosity of the foreground color.
        fonts (Tuple[str, ...]):
            Font families to use in HTML output, in order of
            preference (empty tuple for browser default).
        font_size (NonNegativeFloat | None):
            Font size in pixels for HTML output (None for browser
            default).
        font_weight (NonNegativeInt | None):
            Font weight for HTML output (None for browser
            default).
        line_height (NonNegativeFloat | None):
            Line height multiplier for HTML output (None for
            browser default).
        h_overflow (HorizontalOverflowMode.Literals):
            How to handle text that exceeds the width.
        v_overflow (VerticalOverflowMode.Literals):
            How to handle text that exceeds the height.
        panel (PanelDesign.Literals):
            Visual design of the panel used as container for the
            output. Only `TABLE` is currently supported, which
            displays the output in a table-like grid.
        title_at_top (bool):
            Whether panel titles will be displayed over the panel
            content (True) or below the content (False)
        max_title_height (MaxTitleHeight.Literals):
            Maximum height of the panel title. If `AUTO`, the
            height is determined by the content of the title, up
            to a maximum of two lines. If `ZERO`, the title is not
            displayed at all. If `ONE` or `TWO`, the title is
            displayed with a fixed height of max one or two lines,
            respectively.
        min_panel_width (NonNegativeInt):
            Minimum width in characters per panel.
        min_crop_width (NonNegativeInt):
            Minimum cropping width in characters for panels in
            cases where more than one panel are to be displayed.
            This is for instance used to calculate the number of
            models to display in a Dataset peek(). Only applied if
            `use_min_crop_width` is set to `True`.
            `min_crop_width` must be equal to or larger than
            `min_panel_width`.
        use_min_crop_width (bool):
            Whether the `min_crop_width` value should be
            considered in cases where more than one panel are to
            be displayed, potentially reducing the number of
            displayed panels.
        max_panels_hor (NonNegativeInt | None):
            Maximum number of panels to display horizontally
            side-by-side at the top level. This value also acts as
            a ceiling for nested panels; nested panels cannot
            exceed this limit even if the constant
            `MAX_PANELS_HORIZONTALLY_DEEPLY_NESTED` is set to a
            higher value. If None, there is no limit.
        max_nesting_depth (NonNegativeInt | None):
            Maximum levels of nested panels to display. If None,
            there is no limit.
        justify (Justify.Literals):
            Justification mode for the panel if inside a layout
            panel. This is only used for the panel content.

    Returns:
        If the UI type is Jupyter running in browser, the
        method returns a ReactivelyResizingHtml element which
        is a Jupyter widget to display HTML output in the
        browser. Otherwise, the method returns None.

    Note:
        Any default argument value is overridden by the
        corresponding value in the relevant subsection of the
        UserInterfaceConfig.
    """
    return self._display_according_to_ui_type(
        ui_type=self._extract_ui_type(**kwargs),
        return_output_if_str=False,
        output_method=self._peek,
        **kwargs,
    )

set_orig_model classmethod

set_orig_model(orig_model: TypeForm) -> None

Store the original declared model type on the root field metadata.

PARAMETER DESCRIPTION
orig_model

Original type expression to associate with the model.

TYPE: TypeForm

Source code in src/omnipy/data/model.py
@classmethod
def set_orig_model(cls, orig_model: TypeForm) -> None:
    """Store the original declared model type on the root field metadata.

    Args:
        orig_model: Original type expression to associate with the model.
    """
    cls.__fields__[ROOT_KEY].field_info.extra['orig_model'] = orig_model

snapshot_differs_from_model

snapshot_differs_from_model(model: Model) -> bool

Check whether the stored snapshot differs from another model's content.

PARAMETER DESCRIPTION
model

Model whose current content should be compared with the snapshot.

TYPE: Model

RETURNS DESCRIPTION
bool

True if the snapshot content differs from model.content.

Source code in src/omnipy/data/model.py
def snapshot_differs_from_model(self, model: 'Model') -> bool:
    """Check whether the stored snapshot differs from another model's content.

    Args:
        model: Model whose current content should be compared with the
            snapshot.

    Returns:
        ``True`` if the snapshot content differs from ``model.content``.
    """
    snapshot_wrapper = self._get_snapshot_wrapper()
    return snapshot_wrapper.differs_from(model.content)

snapshot_taken_of_same_model

snapshot_taken_of_same_model(model: Model) -> bool

Check whether the stored snapshot was taken from model itself.

PARAMETER DESCRIPTION
model

Model instance to compare against the snapshot origin.

TYPE: Model

RETURNS DESCRIPTION
bool

True if the snapshot was recorded from the same object identity.

Source code in src/omnipy/data/model.py
def snapshot_taken_of_same_model(self, model: 'Model') -> bool:
    """Check whether the stored snapshot was taken from ``model`` itself.

    Args:
        model: Model instance to compare against the snapshot origin.

    Returns:
        ``True`` if the snapshot was recorded from the same object identity.
    """
    snapshot_wrapper = self._get_snapshot_wrapper()
    return snapshot_wrapper.taken_of_same_obj(model)

to

to(model_cls: type[_OtherModelT]) -> _OtherModelT

Convert this model into another model class by reparsing its data.

PARAMETER DESCRIPTION
model_cls

Destination model class.

TYPE: type[_OtherModelT]

RETURNS DESCRIPTION
_OtherModelT

A new instance of model_cls initialized from this model.

Source code in src/omnipy/data/model.py
def to(self, model_cls: type[_OtherModelT]) -> _OtherModelT:
    """Convert this model into another model class by reparsing its data.

    Args:
        model_cls: Destination model class.

    Returns:
        A new instance of ``model_cls`` initialized from this model.
    """
    return model_cls(self)

to_data

to_data() -> object

Serialize the model into raw Python data.

RETURNS DESCRIPTION
object

The wrapped value converted to plain data, including recursive conversion of nested Omnipy models.

Source code in src/omnipy/data/model.py
def to_data(self) -> object:
    """Serialize the model into raw Python data.

    Returns:
        The wrapped value converted to plain data, including recursive
        conversion of nested Omnipy models.
    """
    return super().dict(by_alias=True)[ROOT_KEY]

to_json

to_json(pretty=True) -> str

Serialize the model to JSON.

PARAMETER DESCRIPTION
pretty

When True, return indented human-readable JSON.

DEFAULT: True

RETURNS DESCRIPTION
str

JSON representation of the model content.

Source code in src/omnipy/data/model.py
def to_json(self, pretty=True) -> str:
    """Serialize the model to JSON.

    Args:
        pretty: When ``True``, return indented human-readable JSON.

    Returns:
        JSON representation of the model content.
    """
    json_content = pyd.BaseModel.json(self)
    if pretty:
        return self._pretty_print_json(json.loads(json_content))
    else:
        return json_content

to_json_schema classmethod

to_json_schema(pretty=True) -> str

Render the model's JSON schema.

PARAMETER DESCRIPTION
pretty

When True, return indented human-readable JSON.

DEFAULT: True

RETURNS DESCRIPTION
str

JSON schema for the model with Omnipy's orig_model metadata removed.

Source code in src/omnipy/data/model.py
@classmethod
def to_json_schema(cls, pretty=True) -> str:
    """Render the model's JSON schema.

    Args:
        pretty: When ``True``, return indented human-readable JSON.

    Returns:
        JSON schema for the model with Omnipy's ``orig_model`` metadata
        removed.
    """
    schema = cls.schema()
    if 'orig_model' in schema:
        del schema['orig_model']

    if pretty:
        return cls._pretty_print_json(schema)
    else:
        return json.dumps(schema)

update_forward_refs classmethod

update_forward_refs(
    calling_module: str | None = None, prev_visited_classes: set[type] | None = None, **localns: Any
) -> None

Resolve forward references for this model and related model bases.

Omnipy extends pydantic's behavior by merging namespaces from both the defining module and the calling module, then propagating the same context through parent model classes. This keeps forward references working when specialized models are defined in one module and used from another.

PARAMETER DESCRIPTION
calling_module

Module name to use as the caller context. When not provided, Omnipy infers it from the call stack.

TYPE: str | None DEFAULT: None

prev_visited_classes

Set used internally to avoid revisiting model classes during recursive propagation.

TYPE: set[type] | None DEFAULT: None

**localns

Additional local names available while resolving forward references.

TYPE: Any DEFAULT: {}

Source code in src/omnipy/data/model.py
@classmethod
def update_forward_refs(
    cls,
    calling_module: str | None = None,
    prev_visited_classes: set[type] | None = None,
    **localns: Any,
) -> None:
    """Resolve forward references for this model and related model bases.

    Omnipy extends pydantic's behavior by merging namespaces from both the
    defining module and the calling module, then propagating the same context
    through parent model classes. This keeps forward references working when
    specialized models are defined in one module and used from another.

    Args:
        calling_module: Module name to use as the caller context. When not
            provided, Omnipy infers it from the call stack.
        prev_visited_classes: Set used internally to avoid revisiting model
            classes during recursive propagation.
        **localns: Additional local names available while resolving forward
            references.
    """
    if prev_visited_classes is None:
        prev_visited_classes = set()
    elif cls in prev_visited_classes:
        return

    # Merge the namespaces of the Model's own module and the calling
    # module to the local namespace for evaluation of forward
    # references, which is necessary for cases where the Model is
    # defined in a different module than where it is used, e.g. when
    # the Model is defined in a library and used by a user in their
    # own code.
    if calling_module is None:
        calling_module = get_calling_module_name()
    own_module_ns, globalns = \
        build_own_module_and_global_namespace_for_forward_refs(cls, calling_module, **localns)

    prev_outer_type = cls._get_root_field().outer_type_
    prev_type = cls._get_root_field().type_

    super().update_forward_refs(**globalns)

    cls._get_root_field().outer_type_ = evaluate_any_forward_refs_if_possible(
        prev_outer_type, **globalns)
    cls._get_root_field().type_ = evaluate_any_forward_refs_if_possible(prev_type, **globalns)
    cls.set_orig_model(evaluate_any_forward_refs_if_possible(cls.get_orig_model(), **globalns))
    if ROOT_KEY in cls.__annotations__:
        cls.__annotations__[ROOT_KEY] = evaluate_any_forward_refs_if_possible(
            cls.__annotations__[ROOT_KEY], **globalns)

    cls._clean_type_caches()

    cls._recursively_set_allow_none(cls._get_root_field())

    cls._prepare_cls_members_to_mimic_model(cls)

    prev_visited_classes.add(cls)

    # Propagate update_forward_refs to parent models but retaining the
    # same calling module. This is needed to ensure the correct
    # context is used to resolve forward references in complex
    # inheritance hierarchies.
    #
    # We explicitly call `update_forward_refs` on immediate parent
    # classes (`__bases__`) instead of relying solely on
    # `super().update_forward_refs()`. This is because `super()`
    # inside this classmethod resolves relative to `Model` in the MRO,
    # silently bypassing custom logic on any intermediate `Model`
    # subclasses. Explicitly propagating through `__bases__` ensures
    # that class-level setups are correctly applied to all parents
    # exactly once, efficiently preventing redundant updates.
    for base in cls.__bases__:
        if is_model_subclass(base) and base is not Model:
            # Merge the current class's own module namespace into
            # localns before propagating, so that pydantic-generated
            # parametrized base classes (which have
            # __module__='omnipy.data.model' rather than the defining
            # module) can still resolve forward refs that only exist
            # in the defining module's namespace.

            extra_ns: dict[str, Any] = {}
            extra_ns.update(**own_module_ns)
            extra_ns.update(**localns)

            base.update_forward_refs(
                calling_module=calling_module,
                prev_visited_classes=prev_visited_classes,
                **extra_ns,
            )

    cls.__name__ = remove_forward_ref_notation(cls.__name__)
    cls.__qualname__ = remove_forward_ref_notation(cls.__qualname__)

update_reactive_views

update_reactive_views()
Source code in src/omnipy/data/_mixins/display.py
def update_reactive_views(self):
    from omnipy import runtime
    assert runtime.objects.reactive is not None
    obj_id_update_flags = runtime.objects.reactive.obj_id_update_flags.value.copy()
    flag = obj_id_update_flags.get(id(self), False)
    obj_id_update_flags[id(self)] = not flag
    runtime.objects.reactive.obj_id_update_flags.set(obj_id_update_flags)

validate classmethod

validate(value: Any) -> Model

Validate a value while preserving Omnipy iterator overrides.

This method is primarily an internal compatibility shim for pydantic's validation API. Omnipy temporarily restores pydantic's original __iter__ behavior when validating model instances so custom iterator proxying does not interfere with validation.

PARAMETER DESCRIPTION
value

Value to validate as an instance of cls.

TYPE: Any

RETURNS DESCRIPTION
Model

A validated model instance.

Source code in src/omnipy/data/model.py
@classmethod
def validate(cls: type['Model'], value: Any) -> 'Model':
    """Validate a value while preserving Omnipy iterator overrides.

    This method is primarily an internal compatibility shim for pydantic's
    validation API. Omnipy temporarily restores pydantic's original
    ``__iter__`` behavior when validating model instances so custom iterator
    proxying does not interfere with validation.

    Args:
        value: Value to validate as an instance of ``cls``.

    Returns:
        A validated model instance.
    """
    # TODO: Doublecheck if validate() method is still needed for pydantic v2

    validate_cls_counts[cls.__name__] += 1
    if is_model_instance(value):

        @contextmanager
        def temporary_set_value_iter_to_pydantic_method() -> Iterator[None]:
            """Temporarily restore pydantic's iterator implementation.

            Returns:
                Iterator[None]: Context manager generator that swaps in the
                    original pydantic ``__iter__`` implementation during
                    validation.
            """
            prev_iter = value.__class__.__iter__
            value.__class__.__iter__ = pyd.GenericModel.__iter__  # type: ignore[method-assign]

            try:
                yield
            finally:
                value.__class__.__iter__ = prev_iter  # type: ignore[method-assign]

        with temporary_set_value_iter_to_pydantic_method():
            return super().validate(value)
    else:
        return super().validate(value)

validate_content

validate_content() -> None

Re-validate the current :attr:content value in place.

RAISES DESCRIPTION
ValidationError

If the current content no longer satisfies the model's declared type.

Source code in src/omnipy/data/model.py
def validate_content(self) -> None:
    """Re-validate the current :attr:`content` value in place.

    Raises:
        ValidationError: If the current content no longer satisfies the
            model's declared type.
    """
    self._validate_and_set_value(self.content)

ModelMetaclass

Bases: DataClassBaseMeta, pyd.ModelMetaclass


              flowchart BT
              omnipy.data.model.ModelMetaclass[ModelMetaclass]
              omnipy.data._data_class_creator.DataClassBaseMeta[DataClassBaseMeta]

                              omnipy.data._data_class_creator.DataClassBaseMeta --> omnipy.data.model.ModelMetaclass
                
                omnipy.util.pydantic.ModelMetaclass --> omnipy.data.model.ModelMetaclass
                


              click omnipy.data.model.ModelMetaclass href "" "omnipy.data.model.ModelMetaclass"
              click omnipy.data._data_class_creator.DataClassBaseMeta href "" "omnipy.data._data_class_creator.DataClassBaseMeta"
            

Metaclass for :class:Model with relaxed None handling.

Omnipy uses this metaclass as a workaround for a pydantic v1 bug affecting nested root models. During certain validation paths, pydantic may check None against the model class too early. Treating None as a temporary instance match lets Omnipy defer the actual None decision to the model's declared type.

ATTRIBUTE DESCRIPTION
data_class_creator

Return the creator object shared by classes using this metaclass.

TYPE: IsDataClassCreator

Source code in src/omnipy/data/model.py
class ModelMetaclass(DataClassBaseMeta, pyd.ModelMetaclass):
    """Metaclass for :class:`Model` with relaxed ``None`` handling.

    Omnipy uses this metaclass as a workaround for a pydantic v1 bug affecting
    nested root models. During certain validation paths, pydantic may check
    ``None`` against the model class too early. Treating ``None`` as a temporary
    instance match lets Omnipy defer the actual ``None`` decision to the model's
    declared type.
    """

    # Hack to overcome bug in pydantic/fields.py (v1.10.13), lines 636-641:
    #
    # if origin is None or origin is CollectionsHashable:
    #     # field is not "typing" object eg. Union, dict, list etc.
    #     # allow None for virtual superclasses of NoneType, e.g. Hashable
    #     if isinstance(self.type_, type) and isinstance(None, self.type_):
    #         self.allow_none = True
    #     return
    #
    # This hinders models (including pure pydantic BaseModels) to be properly considered as
    # subfields, e.g. in `list[MyModel]` as `get_origin(MyModel) is None`. Here, we want allow_none
    # to be set to True so that Model is allowed to validate a None value.
    #
    # TODO: Revisit the need for _ModelMetaclass hack in pydantic v2
    def __instancecheck__(self, instance: Any) -> bool:
        """Report ``None`` as temporarily instance-compatible.

        Args:
            instance: Object being checked against the model class.

        Returns:
            ``True`` when ``instance`` is ``None`` or when the normal metaclass
            instance check succeeds.
        """
        if instance is None:
            return True
        return super().__instancecheck__(instance)

data_class_creator property

data_class_creator: IsDataClassCreator

Return the creator object shared by classes using this metaclass.

is_model_instance

is_model_instance(__obj: object) -> TypeIs[Model]

Check whether an object is an Omnipy model instance.

PARAMETER DESCRIPTION
__obj

Object to test.

TYPE: object

RETURNS DESCRIPTION
TypeIs[Model]

True when __obj is an instance of :class:Model.

Source code in src/omnipy/data/model.py
def is_model_instance(__obj: object) -> 'TypeIs[Model]':
    """Check whether an object is an Omnipy model instance.

    Args:
        __obj: Object to test.

    Returns:
        ``True`` when ``__obj`` is an instance of :class:`Model`.
    """
    return lenient_isinstance(__obj, Model) \
        and not is_none_type(__obj)  # Consequence of _ModelMetaclass hack

is_model_subclass cached

is_model_subclass(__cls: TypeForm) -> TypeIs[type[Model]]

Check whether a type is an Omnipy model subclass.

PARAMETER DESCRIPTION
__cls

Type expression to test.

TYPE: TypeForm

RETURNS DESCRIPTION
TypeIs[type[Model]]

True when __cls is a subclass of :class:Model.

Source code in src/omnipy/data/model.py
@functools.cache
def is_model_subclass(__cls: TypeForm) -> 'TypeIs[type[Model]]':
    """Check whether a type is an Omnipy model subclass.

    Args:
        __cls: Type expression to test.

    Returns:
        ``True`` when ``__cls`` is a subclass of :class:`Model`.
    """
    return lenient_issubclass(__cls, Model) \
        and not is_none_type(__cls)  # Consequence of _ModelMetaclass hack

is_non_omnipy_pydantic_model

is_non_omnipy_pydantic_model(obj: object)

Check whether an object is a pydantic model outside Omnipy's wrappers.

PARAMETER DESCRIPTION
obj

Object to test.

TYPE: object

RETURNS DESCRIPTION

True when obj is a pydantic or generic pydantic model instance that is neither an Omnipy :class:Model nor an Omnipy :class:~omnipy.data.dataset.Dataset.

Source code in src/omnipy/data/model.py
def is_non_omnipy_pydantic_model(obj: object):
    """Check whether an object is a pydantic model outside Omnipy's wrappers.

    Args:
        obj: Object to test.

    Returns:
        ``True`` when ``obj`` is a pydantic or generic pydantic model instance
        that is neither an Omnipy :class:`Model` nor an Omnipy
        :class:`~omnipy.data.dataset.Dataset`.
    """
    mro = type(obj).__mro__
    return mro[0] != pyd.BaseModel \
        and (pyd.BaseModel in mro or pyd.GenericModel in mro) \
        and Model not in mro \
        and Dataset not in mro

is_pure_pydantic_model

is_pure_pydantic_model(obj: object)

Check whether an object is a direct pydantic.BaseModel subclass instance.

PARAMETER DESCRIPTION
obj

Object to test.

TYPE: object

RETURNS DESCRIPTION

True when the object's immediate base class is exactly pydantic.BaseModel.

Source code in src/omnipy/data/model.py
def is_pure_pydantic_model(obj: object):
    """Check whether an object is a direct ``pydantic.BaseModel`` subclass instance.

    Args:
        obj: Object to test.

    Returns:
        ``True`` when the object's immediate base class is exactly
        ``pydantic.BaseModel``.
    """
    return type(obj).__bases__ == (pyd.BaseModel,)

obj_or_model_content_isinstance

obj_or_model_content_isinstance(
    __obj: object, __class_or_tuple: type[_ClassOrTupleT] | tuple[type[_ClassOrTupleT], ...]
) -> TypeIs[_ClassOrTupleT]

Check a plain object or a model's content against a target type.

PARAMETER DESCRIPTION
__obj

Plain object or model instance to inspect.

TYPE: object

__class_or_tuple

Accepted type or tuple of accepted types.

TYPE: type[_ClassOrTupleT] | tuple[type[_ClassOrTupleT], ...]

RETURNS DESCRIPTION
TypeIs[_ClassOrTupleT]

True when __obj itself, or __obj.content for a model, matches __class_or_tuple.

Source code in src/omnipy/data/model.py
def obj_or_model_content_isinstance(
    __obj: object,
    __class_or_tuple: type[_ClassOrTupleT] | tuple[type[_ClassOrTupleT], ...],
) -> TypeIs[_ClassOrTupleT]:
    """Check a plain object or a model's content against a target type.

    Args:
        __obj: Plain object or model instance to inspect.
        __class_or_tuple: Accepted type or tuple of accepted types.

    Returns:
        ``True`` when ``__obj`` itself, or ``__obj.content`` for a model,
        matches ``__class_or_tuple``.
    """
    return isinstance(__obj.content if is_model_instance(__obj) else __obj, __class_or_tuple)

parse_none_according_to_model

parse_none_according_to_model(value, root_model)

Convert None values according to a model's nested type rules.

This helper works around pydantic v1 limitations around nested None handling. It walks the declared model type and injects None or nested model wrappers where Omnipy's type semantics allow them.

PARAMETER DESCRIPTION
value

Candidate value that may contain None entries.

root_model

Model class whose root type should govern the conversion.

RETURNS DESCRIPTION

The original value or a transformed structure with None values normalized according to root_model.

RAISES DESCRIPTION
OmnipyNoneIsNotAllowedError

If None appears where the model type does not allow it.

Source code in src/omnipy/data/model.py
def parse_none_according_to_model(value, root_model):  # IsModel
    """Convert ``None`` values according to a model's nested type rules.

    This helper works around pydantic v1 limitations around nested ``None``
    handling. It walks the declared model type and injects ``None`` or nested
    model wrappers where Omnipy's type semantics allow them.

    Args:
        value: Candidate value that may contain ``None`` entries.
        root_model: Model class whose root type should govern the conversion.

    Returns:
        The original value or a transformed structure with ``None`` values
        normalized according to ``root_model``.

    Raises:
        OmnipyNoneIsNotAllowedError: If ``None`` appears where the model type
            does not allow it.
    """
    outer_type = root_model.outer_type(with_args=True)
    plain_outer_type = root_model.outer_type(with_args=False)
    outer_args = get_args(outer_type)

    if is_model_subclass(outer_type):
        return _parse_none_in_model(outer_type, value)

    if root_model.is_nested_type():
        inner_val_type = root_model.inner_type(with_args=True)

        # Mutable sequences or variable tuples
        if _outer_type_and_value_are_of_types(plain_outer_type, value, (MutableSequence, tuple)):
            return _parse_none_in_mutable_sequence_or_tuple(plain_outer_type, inner_val_type, value)

        # Mappings
        if _outer_type_and_value_are_of_types(plain_outer_type, value, Mapping) and outer_args:
            return _parse_none_in_mapping(plain_outer_type, outer_args, inner_val_type, value)

        if lenient_isinstance(outer_type, TypeVar):
            return _parse_none_in_typevar(inner_val_type)

        if value is None:
            raise OmnipyNoneIsNotAllowedError()

    else:
        union_variants = _split_outer_type_to_union_variants(outer_args)
        flattened_union_variants = _flatten_two_level_tuple(union_variants)

        if any(is_model_subclass(tp_) or _supports_none(tp_) for tp_ in flattened_union_variants):

            # Fixed tuples
            if _outer_type_and_value_are_of_types(plain_outer_type, value, tuple) and outer_args:
                return _parse_none_in_fixed_tuple(plain_outer_type, union_variants, value)

            # Unions
            if is_union(plain_outer_type):
                return _parse_none_in_union(flattened_union_variants, value)

    return value

prepare_value_for_validation_if_dataset_or_model

prepare_value_for_validation_if_dataset_or_model(value: object) -> tuple[bool, object]

Convert model-like inputs to plain data before validation.

PARAMETER DESCRIPTION
value

Candidate value to normalize before validation.

TYPE: object

RETURNS DESCRIPTION
tuple[bool, object]

tuple[bool, object]: Flag indicating whether a conversion was applied, together with the normalized value.

Source code in src/omnipy/data/model.py
def prepare_value_for_validation_if_dataset_or_model(value: object,) -> tuple[bool, object]:
    """Convert model-like inputs to plain data before validation.

    Args:
        value: Candidate value to normalize before validation.

    Returns:
        tuple[bool, object]: Flag indicating whether a conversion was applied, together
            with the normalized value.
    """
    if is_dataset_instance(value):
        return True, value.to_data()
    if is_model_instance(value):
        return True, value.to_data()
    elif is_non_omnipy_pydantic_model(value):
        return True, cast(pyd.BaseModel, value).dict(by_alias=True)
    return False, value