From 43ff3503dc98e366bf5f677d01a654dfcad7b779 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Tue, 13 Aug 2024 23:38:53 -0700 Subject: [PATCH] more texts. Fix coercion with ndarrays and vectordata, incl numpydantic 1.3.3 making ndarray types callable --- nwb_linkml/pdm.lock | 231 ++++++++------------ nwb_linkml/pyproject.toml | 2 +- nwb_linkml/src/nwb_linkml/includes/hdmf.py | 43 ++-- nwb_linkml/tests/test_includes/test_hdmf.py | 130 ++++++++++- 4 files changed, 241 insertions(+), 165 deletions(-) diff --git a/nwb_linkml/pdm.lock b/nwb_linkml/pdm.lock index e3af7cb..3482eac 100644 --- a/nwb_linkml/pdm.lock +++ b/nwb_linkml/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev", "plot", "tests"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:ed633a147948a9923f6b3a99690d5d8bad0b4b8c0d528abe62d132b05d1d9f39" +content_hash = "sha256:20f4f69a117fab515291f53ff39dfd1e13e3c8cbd399f1f7ce308cbea7deeaf0" [[metadata.targets]] requires_python = ">=3.10,<3.13" @@ -102,7 +102,7 @@ name = "blinker" version = "1.8.2" requires_python = ">=3.8" summary = "Fast, simple object-to-object and broadcast signaling" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, @@ -219,7 +219,7 @@ name = "click" version = "8.1.7" requires_python = ">=3.7" summary = "Composable command line interface toolkit" -groups = ["default", "dev", "plot", "tests"] +groups = ["default", "dev", "plot"] dependencies = [ "colorama; platform_system == \"Windows\"", "importlib-metadata; python_version < \"3.8\"", @@ -242,81 +242,89 @@ files = [ [[package]] name = "coverage" -version = "6.5.0" -requires_python = ">=3.7" +version = "7.6.1" +requires_python = ">=3.8" summary = "Code coverage measurement for Python" groups = ["dev", "tests"] files = [ - {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, - {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, - {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, - {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, - {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, - {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, - {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, - {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [[package]] name = "coverage" -version = "6.5.0" +version = "7.6.1" extras = ["toml"] -requires_python = ">=3.7" +requires_python = ">=3.8" summary = "Code coverage measurement for Python" groups = ["dev", "tests"] dependencies = [ - "coverage==6.5.0", + "coverage==7.6.1", "tomli; python_full_version <= \"3.11.0a6\"", ] files = [ - {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, - {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, - {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, - {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, - {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, - {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, - {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, - {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, -] - -[[package]] -name = "coveralls" -version = "3.3.1" -requires_python = ">= 3.5" -summary = "Show coverage stats online via coveralls.io" -groups = ["dev", "tests"] -dependencies = [ - "coverage!=6.0.*,!=6.1,!=6.1.1,<7.0,>=4.1", - "docopt>=0.6.1", - "requests>=1.0.0", -] -files = [ - {file = "coveralls-3.3.1-py2.py3-none-any.whl", hash = "sha256:f42015f31d386b351d4226389b387ae173207058832fbf5c8ec4b40e27b16026"}, - {file = "coveralls-3.3.1.tar.gz", hash = "sha256:b32a8bb5d2df585207c119d6c01567b81fba690c9c10a753bfe27a335bfc43ea"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [[package]] @@ -340,7 +348,7 @@ name = "dash" version = "2.17.1" requires_python = ">=3.8" summary = "A Python framework for building reactive web-apps. Developed by Plotly." -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "Flask<3.1,>=1.0.4", "Werkzeug<3.1", @@ -364,7 +372,7 @@ files = [ name = "dash-core-components" version = "2.0.0" summary = "Core component suite for Dash" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "dash_core_components-2.0.0-py3-none-any.whl", hash = "sha256:52b8e8cce13b18d0802ee3acbc5e888cb1248a04968f962d63d070400af2e346"}, {file = "dash_core_components-2.0.0.tar.gz", hash = "sha256:c6733874af975e552f95a1398a16c2ee7df14ce43fa60bb3718a3c6e0b63ffee"}, @@ -374,7 +382,7 @@ files = [ name = "dash-cytoscape" version = "0.3.0" summary = "A Component Library for Dash aimed at facilitating network visualization in Python, wrapped around Cytoscape.js" -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "dash", ] @@ -387,7 +395,7 @@ files = [ name = "dash-html-components" version = "2.0.0" summary = "Vanilla HTML components for Dash" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "dash_html_components-2.0.0-py3-none-any.whl", hash = "sha256:b42cc903713c9706af03b3f2548bda4be7307a7cf89b7d6eae3da872717d1b63"}, {file = "dash_html_components-2.0.0.tar.gz", hash = "sha256:8703a601080f02619a6390998e0b3da4a5daabe97a1fd7a9cebc09d015f26e50"}, @@ -397,7 +405,7 @@ files = [ name = "dash-table" version = "5.0.0" summary = "Dash table" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "dash_table-5.0.0-py3-none-any.whl", hash = "sha256:19036fa352bb1c11baf38068ec62d172f0515f73ca3276c79dee49b95ddc16c9"}, {file = "dash_table-5.0.0.tar.gz", hash = "sha256:18624d693d4c8ef2ddec99a6f167593437a7ea0bf153aa20f318c170c5bc7308"}, @@ -417,15 +425,6 @@ files = [ {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, ] -[[package]] -name = "docopt" -version = "0.6.2" -summary = "Pythonic argument parser, that will make you smile" -groups = ["dev", "tests"] -files = [ - {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, -] - [[package]] name = "et-xmlfile" version = "1.1.0" @@ -454,7 +453,7 @@ name = "flask" version = "3.0.3" requires_python = ">=3.8" summary = "A simple framework for building complex web applications." -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "Jinja2>=3.1.2", "Werkzeug>=3.0.0", @@ -496,17 +495,6 @@ files = [ {file = "future_fstrings-1.2.0.tar.gz", hash = "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089"}, ] -[[package]] -name = "gprof2dot" -version = "2024.6.6" -requires_python = ">=3.8" -summary = "Generate a dot graph from the output of several profilers." -groups = ["dev", "tests"] -files = [ - {file = "gprof2dot-2024.6.6-py2.py3-none-any.whl", hash = "sha256:45b14ad7ce64e299c8f526881007b9eb2c6b75505d5613e96e66ee4d5ab33696"}, - {file = "gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab"}, -] - [[package]] name = "graphviz" version = "0.20.3" @@ -608,7 +596,7 @@ name = "importlib-metadata" version = "8.2.0" requires_python = ">=3.8" summary = "Read metadata from Python packages" -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "typing-extensions>=3.6.4; python_version < \"3.8\"", "zipp>=0.5", @@ -661,7 +649,7 @@ name = "itsdangerous" version = "2.2.0" requires_python = ">=3.8" summary = "Safely pass data to untrusted environments and back." -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, @@ -672,7 +660,7 @@ name = "jinja2" version = "3.1.4" requires_python = ">=3.7" summary = "A very fast and expressive template engine." -groups = ["default", "dev", "plot", "tests"] +groups = ["default", "plot"] dependencies = [ "MarkupSafe>=2.0", ] @@ -915,7 +903,7 @@ name = "markupsafe" version = "2.1.5" requires_python = ">=3.7" summary = "Safely add untrusted strings to HTML/XML markup." -groups = ["default", "dev", "plot", "tests"] +groups = ["default", "plot"] files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -977,7 +965,7 @@ name = "nest-asyncio" version = "1.6.0" requires_python = ">=3.5" summary = "Patch asyncio to allow nested event loops" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1036,7 +1024,7 @@ files = [ [[package]] name = "numpydantic" -version = "1.3.1" +version = "1.3.3" requires_python = "<4.0,>=3.9" summary = "Type and shape validation and serialization for numpy arrays in pydantic models" groups = ["default"] @@ -1046,8 +1034,8 @@ dependencies = [ "typing-extensions>=4.11.0; python_version < \"3.11\"", ] files = [ - {file = "numpydantic-1.3.1-py3-none-any.whl", hash = "sha256:c0a37c093fcd0e4ed52c4556f4e804eec76fcf924c546e475509e662336f9f61"}, - {file = "numpydantic-1.3.1.tar.gz", hash = "sha256:d61868d7912f2dfee9906bd989399d74f470dee10d5028409c2f5d39529fc4af"}, + {file = "numpydantic-1.3.3-py3-none-any.whl", hash = "sha256:e002767252b1b77abb7715834ab7cbf58964baddae44863710f09e71b23287e4"}, + {file = "numpydantic-1.3.3.tar.gz", hash = "sha256:1cc2744f7b5fbcecd51a64fafaf8c9a564bb296336a566a16be97ba7b1c28698"}, ] [[package]] @@ -1166,7 +1154,7 @@ name = "plotly" version = "5.23.0" requires_python = ">=3.8" summary = "An open-source, interactive data visualization library for Python" -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "packaging", "tenacity>=6.2.0", @@ -1458,35 +1446,6 @@ files = [ {file = "pytest-logging-2015.11.4.tar.gz", hash = "sha256:cec5c85ecf18aab7b2ead5498a31b9f758680ef5a902b9054ab3f2bdbb77c896"}, ] -[[package]] -name = "pytest-md" -version = "0.2.0" -requires_python = ">=3.6" -summary = "Plugin for generating Markdown reports for pytest results" -groups = ["dev", "tests"] -dependencies = [ - "pytest>=4.2.1", -] -files = [ - {file = "pytest-md-0.2.0.tar.gz", hash = "sha256:3b248d5b360ea5198e05b4f49c7442234812809a63137ec6cdd3643a40cf0112"}, - {file = "pytest_md-0.2.0-py3-none-any.whl", hash = "sha256:4c4cd16fea6d1485e87ee254558712c804a96d2aa9674b780e7eb8fb6526e1d1"}, -] - -[[package]] -name = "pytest-profiling" -version = "1.7.0" -summary = "Profiling plugin for py.test" -groups = ["dev", "tests"] -dependencies = [ - "gprof2dot", - "pytest", - "six", -] -files = [ - {file = "pytest-profiling-1.7.0.tar.gz", hash = "sha256:93938f147662225d2b8bd5af89587b979652426a8a6ffd7e73ec4a23e24b7f29"}, - {file = "pytest_profiling-1.7.0-py2.py3-none-any.whl", hash = "sha256:999cc9ac94f2e528e3f5d43465da277429984a1c237ae9818f8cfd0b06acb019"}, -] - [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1670,7 +1629,7 @@ files = [ name = "retrying" version = "1.3.4" summary = "Retrying" -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "six>=1.7.0", ] @@ -1858,13 +1817,13 @@ files = [ [[package]] name = "setuptools" -version = "72.1.0" +version = "72.2.0" requires_python = ">=3.8" summary = "Easily download, build, install, upgrade, and uninstall Python packages" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ - {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, - {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, + {file = "setuptools-72.2.0-py3-none-any.whl", hash = "sha256:f11dd94b7bae3a156a95ec151f24e4637fb4fa19c878e4d191bfb8b2d82728c4"}, + {file = "setuptools-72.2.0.tar.gz", hash = "sha256:80aacbf633704e9c8bfa1d99fa5dd4dc59573efcf9e4042c13d3bcef91ac2ef9"}, ] [[package]] @@ -1987,7 +1946,7 @@ name = "tenacity" version = "9.0.0" requires_python = ">=3.8" summary = "Retry code until it succeeds" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, @@ -2135,7 +2094,7 @@ name = "werkzeug" version = "3.0.3" requires_python = ">=3.8" summary = "The comprehensive WSGI web application library." -groups = ["dev", "plot", "tests"] +groups = ["plot"] dependencies = [ "MarkupSafe>=2.1.1", ] @@ -2190,7 +2149,7 @@ name = "zipp" version = "3.20.0" requires_python = ">=3.8" summary = "Backport of pathlib-compatible object wrapper for zip files" -groups = ["dev", "plot", "tests"] +groups = ["plot"] files = [ {file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"}, {file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"}, diff --git a/nwb_linkml/pyproject.toml b/nwb_linkml/pyproject.toml index ffe0f54..f149733 100644 --- a/nwb_linkml/pyproject.toml +++ b/nwb_linkml/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "pydantic-settings>=2.0.3", "tqdm>=4.66.1", 'typing-extensions>=4.12.2;python_version<"3.11"', - "numpydantic>=1.3.1", + "numpydantic>=1.3.3", "black>=24.4.2", "pandas>=2.2.2", ] diff --git a/nwb_linkml/src/nwb_linkml/includes/hdmf.py b/nwb_linkml/src/nwb_linkml/includes/hdmf.py index e4b9ff1..6c0c8bc 100644 --- a/nwb_linkml/src/nwb_linkml/includes/hdmf.py +++ b/nwb_linkml/src/nwb_linkml/includes/hdmf.py @@ -49,7 +49,7 @@ class DynamicTableMixin(BaseModel): """ model_config = ConfigDict(extra="allow") - __pydantic_extra__: Dict[str, Union[list, "NDArray", "VectorDataMixin"]] + __pydantic_extra__: Dict[str, Union["VectorDataMixin", "VectorIndexMixin", "NDArray", list]] NON_COLUMN_FIELDS: ClassVar[tuple[str]] = ( "name", "colnames", @@ -249,8 +249,9 @@ class DynamicTableMixin(BaseModel): model["colnames"] = colnames return model - @model_validator(mode="after") - def cast_extra_columns(self) -> "DynamicTableMixin": + @model_validator(mode="before") + @classmethod + def cast_extra_columns(cls, model: Dict[str, Any]) -> Dict: """ If extra columns are passed as just lists or arrays, cast to VectorData before we resolve targets for VectorData and VectorIndex pairs. @@ -258,22 +259,20 @@ class DynamicTableMixin(BaseModel): See :meth:`.cast_specified_columns` for handling columns in the class specification """ # if columns are not in the specification, cast to a generic VectorData - for key, val in self.__pydantic_extra__.items(): + for key, val in model.items(): + if key in cls.model_fields: + continue if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - self.__pydantic_extra__[key] = VectorIndex( - name=key, description="", value=val - ) + model[key] = VectorIndex(name=key, description="", value=val) else: - self.__pydantic_extra__[key] = VectorData( - name=key, description="", value=val - ) + model[key] = VectorData(name=key, description="", value=val) except ValidationError as e: raise ValidationError( f"field {key} cannot be cast to VectorData from {val}" ) from e - return self + return model @model_validator(mode="after") def resolve_targets(self) -> "DynamicTableMixin": @@ -285,6 +284,8 @@ class DynamicTableMixin(BaseModel): # find an index idx = None for field_name in self.model_fields_set: + if field_name in self.NON_COLUMN_FIELDS or field_name == key: + continue # implicit name-based index field = getattr(self, field_name) if isinstance(field, VectorIndex) and ( @@ -323,17 +324,23 @@ class DynamicTableMixin(BaseModel): """ try: return handler(val) - except ValidationError: + except ValidationError as e: annotation = cls.model_fields[info.field_name].annotation if type(annotation).__name__ == "_UnionGenericAlias": annotation = annotation.__args__[0] - return handler( - annotation( - val, - name=info.field_name, - description=cls.model_fields[info.field_name].description, + try: + # should pass if we're supposed to be a VectorData column + # don't want to override intention here by insisting that it is + # *actually* a VectorData column in case an NDArray has been specified for now + return handler( + annotation( + val, + name=info.field_name, + description=cls.model_fields[info.field_name].description, + ) ) - ) + except Exception: + raise e class VectorDataMixin(BaseModel, Generic[T]): diff --git a/nwb_linkml/tests/test_includes/test_hdmf.py b/nwb_linkml/tests/test_includes/test_hdmf.py index bde829b..c5a164f 100644 --- a/nwb_linkml/tests/test_includes/test_hdmf.py +++ b/nwb_linkml/tests/test_includes/test_hdmf.py @@ -1,6 +1,8 @@ import numpy as np import pandas as pd +import pytest from numpydantic import NDArray, Shape +from pydantic import ValidationError from nwb_linkml.includes import hdmf from nwb_linkml.includes.hdmf import DynamicTableMixin, VectorDataMixin, VectorIndexMixin @@ -289,17 +291,125 @@ def test_dynamictable_mixin_getattr(): """ class MyDT(DynamicTableMixin): - existing_col: NDArray[Shape["* col"], int] - - class AModel(DynamicTableMixin): - col: hdmf.VectorData[NDArray[Shape["3, 3"], int]] + existing_col: hdmf.VectorData[NDArray[Shape["* col"], int]] col = hdmf.VectorData(value=np.arange(10)) inst = MyDT(existing_col=col) - # regular lookup for attrs that exist - # pdb.set_trace() - # inst.existing_col - # assert inst.existing_col == col - # df lookup otherwise - # inst.columns + # regular lookup for attrs that exist + assert isinstance(inst.existing_col, hdmf.VectorData) + assert all(inst.existing_col.value == col.value) + + # df lookup for thsoe that don't + assert isinstance(inst.columns, pd.Index) + + +def test_dynamictable_coercion(): + """ + Dynamictable should coerce arrays into vectordata objects for known and unknown cols + """ + + class MyDT(DynamicTableMixin): + existing_col: hdmf.VectorData[NDArray[Shape["* col"], int]] + + cols = { + "existing_col": np.arange(10), + "new_col_1": np.arange(10), + } + inst = MyDT(**cols) + assert isinstance(inst.existing_col, hdmf.VectorData) + assert isinstance(inst.new_col_1, hdmf.VectorData) + assert all(inst.existing_col.value == np.arange(10)) + assert all(inst.new_col_1.value == np.arange(10)) + + +def test_dynamictable_create_id(): + class MyDT(DynamicTableMixin): + existing_col: hdmf.VectorData[NDArray[Shape["* col"], int]] + + cols = { + "existing_col": np.arange(10), + } + inst = MyDT(**cols) + + assert all(inst.id == np.arange(10)) + + +def test_dynamictable_resolve_index(): + """ + Dynamictable should resolve and connect data to indices, explicit and implicit + """ + + class MyDT(DynamicTableMixin): + existing_col: hdmf.VectorData[NDArray[Shape["* col"], int]] + + cols = { + "existing_col": np.arange(10), + "new_col_1": hdmf.VectorData(value=np.arange(10)), + "new_col_2": hdmf.VectorData(value=np.arange(10)), + } + # explicit index with mismatching name + cols["weirdname_index"] = hdmf.VectorIndex(value=np.arange(10), target=cols["new_col_1"]) + # implicit index with matching name + cols["new_col_2_index"] = hdmf.VectorIndex(value=np.arange(10)) + + inst = MyDT(**cols) + assert inst.weirdname_index.target is inst.new_col_1 + assert inst.new_col_2_index.target is inst.new_col_2 + assert inst.new_col_1._index is inst.weirdname_index + assert inst.new_col_2._index is inst.new_col_2_index + + +def dynamictable_assert_equal_length(): + """ + Dynamictable validates that columns are of equal length + """ + + class MyDT(DynamicTableMixin): + existing_col: NDArray[Shape["* col"], int] + + cols = { + "existing_col": np.arange(10), + "new_col_1": hdmf.VectorData(value=np.arange(11)), + } + with pytest.raises(ValidationError, pattern="Columns are not of equal length"): + _ = MyDT(**cols) + + cols = { + "existing_col": np.arange(11), + "new_col_1": hdmf.VectorData(value=np.arange(10)), + } + with pytest.raises(ValidationError, pattern="Columns are not of equal length"): + _ = MyDT(**cols) + + # wrong lengths are fine as long as the index is good + cols = { + "existing_col": np.arange(10), + "new_col_1": hdmf.VectorData(value=np.arange(100)), + "new_col_1_index": hdmf.VectorIndex(value=np.arange(0, 100, 10) + 10), + } + _ = MyDT(**cols) + + # but not fine if the index is not good + cols = { + "existing_col": np.arange(10), + "new_col_1": hdmf.VectorData(value=np.arange(100)), + "new_col_1_index": hdmf.VectorIndex(value=np.arange(0, 100, 5) + 5), + } + with pytest.raises(ValidationError, pattern="Columns are not of equal length"): + _ = MyDT(**cols) + + +def test_vectordata_generic_numpydantic_validation(): + """ + Using VectorData as a generic with a numpydantic array annotation should still validate + + Simple test here because numpydantic validation is tested in numpydantic itself, + we just want to check that the annotations work as validation and it doesn't just + """ + + class MyDT(DynamicTableMixin): + existing_col: NDArray[Shape["3 col"], int] + + with pytest.raises(ValidationError): + _ = MyDT(existing_col=np.zeros((4, 5, 6), dtype=int))