Skip to content

Instantly share code, notes, and snippets.

@rly
Created June 17, 2023 12:29
Show Gist options
  • Save rly/f33b9e9bb049ad5759fc631349bbe867 to your computer and use it in GitHub Desktop.
Save rly/f33b9e9bb049ad5759fc631349bbe867 to your computer and use it in GitHub Desktop.
Test behavior of PyNWB/HDMF with an attribute spec that has a non-text or non-scalar default value.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "a1d8169c-c17f-48b4-93df-3f0c1f8f24af",
"metadata": {},
"source": [
"## Question: Can you make an NWB/HDMF spec with an attribute that has a non-text or non-scalar default value?\n",
"Answer: Yes, but the default value will be read by PyNWB/HDMF as one of the default Python types str, int, float, and if it is non-scalar, it will be read as a list or list of lists. On write, a dtype precision can be imposed. As in normal PyNWB/HDMF, consistency of dtypes within a list or list of lists (as opposed to a numpy array) is not checked."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "afad9520-af79-44c9-8975-81c597cf672e",
"metadata": {},
"outputs": [],
"source": [
"from pynwb.spec import NWBGroupSpec, NWBAttributeSpec\n",
"from pynwb.spec import NWBNamespaceBuilder, export_spec"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d53d11d8-15c0-40b3-8002-5099aa9234eb",
"metadata": {},
"outputs": [],
"source": [
"ns_builder = NWBNamespaceBuilder(\n",
" doc=\"test\",\n",
" name=\"ndx-spec-non-string-value\",\n",
" version=\"0.1.0\",\n",
" author=\"Ryan Ly\",\n",
" contact=\"rly@lbl.gov\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "fc70c0fd-f2f4-4561-898a-f1f575f2ae82",
"metadata": {},
"outputs": [],
"source": [
"test_spec1 = NWBGroupSpec(\n",
" neurodata_type_def='TestDefaultValueIntScalar',\n",
" neurodata_type_inc=\"NWBDataInterface\",\n",
" doc=\"test\",\n",
" attributes = [\n",
" NWBAttributeSpec(\n",
" name=\"test_attribute\",\n",
" dtype=\"int\",\n",
" doc=\"test\",\n",
" default_value=10,\n",
" ),\n",
" ],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f2bbc4b0-da4e-4d1c-a5b4-b05a7ac5eabc",
"metadata": {},
"outputs": [],
"source": [
"test_spec2 = NWBGroupSpec(\n",
" neurodata_type_def='TestDefaultValueInt2D',\n",
" neurodata_type_inc=\"NWBDataInterface\",\n",
" doc=\"test\",\n",
" attributes = [\n",
" NWBAttributeSpec(\n",
" name=\"test_attribute\",\n",
" dtype=\"int64\",\n",
" doc=\"test\",\n",
" shape=[None, None],\n",
" default_value=[[1, 2, 3], [4, 5, 6]],\n",
" # NOTE that lists allow mixing of dtypes\n",
" ),\n",
" ],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "62e532fb-d22e-4998-87e0-1c2a144c1129",
"metadata": {},
"outputs": [],
"source": [
"test_spec3 = NWBGroupSpec(\n",
" neurodata_type_def='TestDefaultValueFloat2D',\n",
" neurodata_type_inc=\"NWBDataInterface\",\n",
" doc=\"test\",\n",
" attributes = [\n",
" NWBAttributeSpec(\n",
" name=\"test_attribute\",\n",
" dtype=\"float\",\n",
" doc=\"test\",\n",
" shape=[None, None],\n",
" default_value=[[1., 2., 3.], [4.1, 5.1, 6.1]],\n",
" ),\n",
" ],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "873d8a3e-3502-4ebc-bfe2-5f92958f33de",
"metadata": {},
"outputs": [],
"source": [
"new_data_types = [test_spec1, test_spec2, test_spec3]"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "7e94d8a3-526c-4f78-a0a4-ad5a7801ce07",
"metadata": {},
"outputs": [],
"source": [
"from pathlib import Path\n",
"output_dir = \"ndx-spec-non-string-value\"\n",
"Path(output_dir).mkdir(exist_ok=True)\n",
"export_spec(ns_builder, new_data_types, output_dir)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "87d5908b-680d-409d-9d30-9b9b8b6a21fc",
"metadata": {},
"outputs": [],
"source": [
"from pynwb import get_class, load_namespaces\n",
"load_namespaces(\"ndx-spec-non-string-value/ndx-spec-non-string-value.namespace.yaml\");"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "98f5cd33-c89c-434d-84e5-5363b21a6c96",
"metadata": {},
"outputs": [],
"source": [
"TestDefaultValueIntScalar = get_class(\"TestDefaultValueIntScalar\", \"ndx-spec-non-string-value\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "b646b5af-75ea-4ca8-9e17-96c499ed3e3d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"obj abc.TestDefaultValueIntScalar at 0x4815574528\n",
"Fields:\n",
" test_attribute: 10"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"TestDefaultValueIntScalar(name=\"obj\")"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "7100f942-5746-4f3b-b51e-a7d97576132b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"obj abc.TestDefaultValueIntScalar at 0x4815576688\n",
"Fields:\n",
" test_attribute: 20"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"TestDefaultValueIntScalar(name=\"obj\", test_attribute=20)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "baecc893-07e6-4878-bddc-4441b057d1fd",
"metadata": {},
"outputs": [],
"source": [
"# TestDefaultValueIntScalar(name=\"obj\", test_attribute=\"20\")\n",
"# generates error:\n",
"# TypeError: CustomClassGenerator.set_init.<locals>.__init__: incorrect type for 'test_attribute' (got 'str', expected 'int, int32 or int64')"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "29df90cc-7f7d-4628-9c44-f6502bf2e14f",
"metadata": {},
"outputs": [],
"source": [
"TestDefaultValueInt2D = get_class(\"TestDefaultValueInt2D\", \"ndx-spec-non-string-value\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "d5ebc1d3-386d-485d-90db-a81f01f4b6de",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"obj abc.TestDefaultValueInt2D at 0x4815575344\n",
"Fields:\n",
" test_attribute: [[1 2 3]\n",
" [4 5 6]]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"TestDefaultValueInt2D(name=\"obj\")"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "fcf3ce5d-11e7-482c-ad55-76915139970f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[[1, 2, 3], [4, 5, 6]]"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"TestDefaultValueInt2D(name=\"obj\").test_attribute"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "12ed44c2-b2c8-4588-bec9-14cd67c57fb5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"errors: []\n",
"<class 'numpy.ndarray'>\n",
"<class 'numpy.dtype[int64]'>\n",
"[[1 2 3]\n",
" [4 5 6]]\n"
]
}
],
"source": [
"from pynwb import NWBFile, NWBHDF5IO, validate\n",
"import datetime\n",
"\n",
"nwbfile = NWBFile(\n",
" session_description=\"session_description\",\n",
" identifier=\"identifier\",\n",
" session_start_time=datetime.datetime.now(datetime.timezone.utc),\n",
")\n",
"\n",
"obj = TestDefaultValueInt2D(name=\"obj\")\n",
"nwbfile.add_acquisition(obj)\n",
"\n",
"filename = \"ndx-spec-non-string-value/test_out.nwb\"\n",
"\n",
"with NWBHDF5IO(filename, \"w\") as io:\n",
" io.write(nwbfile)\n",
"\n",
"with NWBHDF5IO(filename, \"r\") as io:\n",
" errors = validate(io)\n",
" print(\"errors:\", errors)\n",
" nwbfile = io.read()\n",
" print(type(nwbfile.acquisition[\"obj\"].test_attribute))\n",
" print(type(nwbfile.acquisition[\"obj\"].test_attribute.dtype))\n",
" print(nwbfile.acquisition[\"obj\"].test_attribute)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "120988e2-41bd-4c3b-8384-c35efbc9640c",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/rly/mambaforge/envs/test/lib/python3.10/site-packages/hdmf/build/objectmapper.py:260: DtypeConversionWarning: Spec 'TestDefaultValueInt2D/test_attribute': Value with data type float64 is being converted to data type int64 as specified.\n",
" warnings.warn(full_warning_msg, DtypeConversionWarning)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"errors: []\n",
"<class 'numpy.ndarray'>\n",
"<class 'numpy.dtype[int64]'>\n",
"[[1 2]\n",
" [3 4]]\n"
]
}
],
"source": [
"from pynwb import NWBFile, NWBHDF5IO, validate\n",
"import datetime\n",
"\n",
"nwbfile = NWBFile(\n",
" session_description=\"session_description\",\n",
" identifier=\"identifier\",\n",
" session_start_time=datetime.datetime.now(datetime.timezone.utc),\n",
")\n",
"\n",
"obj = TestDefaultValueInt2D(name=\"obj\", test_attribute=[[1, 2.1], [3, 4]])\n",
"nwbfile.add_acquisition(obj)\n",
"\n",
"filename = \"ndx-spec-non-string-value/test_out.nwb\"\n",
"\n",
"with NWBHDF5IO(filename, \"w\") as io:\n",
" io.write(nwbfile)\n",
"\n",
"with NWBHDF5IO(filename, \"r\") as io:\n",
" errors = validate(io)\n",
" print(\"errors:\", errors)\n",
" nwbfile = io.read()\n",
" print(type(nwbfile.acquisition[\"obj\"].test_attribute))\n",
" print(type(nwbfile.acquisition[\"obj\"].test_attribute.dtype))\n",
" print(nwbfile.acquisition[\"obj\"].test_attribute)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "ecbdc40a-9a5b-4781-aed6-1ba4f76e2bb6",
"metadata": {},
"outputs": [],
"source": [
"TestDefaultValueFloat2D = get_class(\"TestDefaultValueFloat2D\", \"ndx-spec-non-string-value\")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "1bad18ec-6d9d-4e39-bd7a-464a54c30006",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"obj abc.TestDefaultValueFloat2D at 0x4816245264\n",
"Fields:\n",
" test_attribute: [[1. 2. 3. ]\n",
" [4.1 5.1 6.1]]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"TestDefaultValueFloat2D(name=\"obj\")"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "b4661159-6e41-4cbb-84a4-ff65393cfc24",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"float"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(TestDefaultValueFloat2D(name=\"obj\").test_attribute[0][0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cf3aefd9-a0a7-48a0-9b46-7fd28563df07",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment