-
-
Save stephenworsley/7716fdba4cc634e73454462ad60b3f67 to your computer and use it in GitHub Desktop.
Warning Duplication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"id": "c884f567-84fb-4352-aacd-58f18bd0399c", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import iris" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 47, | |
"id": "6b1718fb-14a7-47b9-bf66-e094173ec19f", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import iris.tests\n", | |
"src_file = iris.tests.get_data_path((\"NetCDF\", \"regrid\", \"regrid_template_global_latlon.nc\"))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "69a563d6-b177-4875-9974-09c64df21128", | |
"metadata": {}, | |
"source": [ | |
"## Warning Duplication" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "be65774a-c9c5-4804-a6c2-3983522e3570", | |
"metadata": {}, | |
"source": [ | |
"Some cubes give warnings when they load. This is expected behaviour." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 48, | |
"id": "25c67fb8-3bd2-4fd8-9371-65cafb2aeeb4", | |
"metadata": { | |
"scrolled": true | |
}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/1165832100.py:1: FutureWarning: Ignoring a datum in netCDF load for consistency with existing behaviour. In a future version of Iris, this datum will be applied. To apply the datum when loading, use the iris.FUTURE.datum_support flag.\n", | |
" iris.load_cube(src_file)\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/html": [ | |
"\n", | |
"<style>\n", | |
" a.iris {\n", | |
" text-decoration: none !important;\n", | |
" }\n", | |
" table.iris {\n", | |
" white-space: pre;\n", | |
" border: 1px solid;\n", | |
" border-color: #9c9c9c;\n", | |
" font-family: monaco, monospace;\n", | |
" }\n", | |
" th.iris {\n", | |
" background: #303f3f;\n", | |
" color: #e0e0e0;\n", | |
" border-left: 1px solid;\n", | |
" border-color: #9c9c9c;\n", | |
" font-size: 1.05em;\n", | |
" min-width: 50px;\n", | |
" max-width: 125px;\n", | |
" }\n", | |
" tr.iris :first-child {\n", | |
" border-right: 1px solid #9c9c9c !important;\n", | |
" }\n", | |
" td.iris-title {\n", | |
" background: #d5dcdf;\n", | |
" border-top: 1px solid #9c9c9c;\n", | |
" font-weight: bold;\n", | |
" }\n", | |
" .iris-word-cell {\n", | |
" text-align: left !important;\n", | |
" white-space: pre;\n", | |
" }\n", | |
" .iris-subheading-cell {\n", | |
" padding-left: 2em !important;\n", | |
" }\n", | |
" .iris-inclusion-cell {\n", | |
" padding-right: 1em !important;\n", | |
" }\n", | |
" .iris-panel-body {\n", | |
" padding-top: 0px;\n", | |
" }\n", | |
" .iris-panel-title {\n", | |
" padding-left: 3em;\n", | |
" }\n", | |
" .iris-panel-title {\n", | |
" margin-top: 7px;\n", | |
" }\n", | |
"</style>\n", | |
"<table class=\"iris\" id=\"140074740537376\">\n", | |
" <tr class=\"iris\">\n", | |
"<th class=\"iris iris-word-cell\">Sample Grid (unknown)</th>\n", | |
"<th class=\"iris iris-word-cell\">latitude</th>\n", | |
"<th class=\"iris iris-word-cell\">longitude</th>\n", | |
"</tr>\n", | |
" <tr class=\"iris\">\n", | |
"<td class=\"iris-word-cell iris-subheading-cell\">Shape</td>\n", | |
"<td class=\"iris iris-inclusion-cell\">180</td>\n", | |
"<td class=\"iris iris-inclusion-cell\">360</td>\n", | |
"</tr>\n", | |
" <tr class=\"iris\">\n", | |
" <td class=\"iris-title iris-word-cell\">Dimension coordinates</td>\n", | |
" <td class=\"iris-title\"></td>\n", | |
" <td class=\"iris-title\"></td>\n", | |
"</tr>\n", | |
"<tr class=\"iris\">\n", | |
" <td class=\"iris-word-cell iris-subheading-cell\">\tlatitude</td>\n", | |
" <td class=\"iris-inclusion-cell\">x</td>\n", | |
" <td class=\"iris-inclusion-cell\">-</td>\n", | |
"</tr>\n", | |
"<tr class=\"iris\">\n", | |
" <td class=\"iris-word-cell iris-subheading-cell\">\tlongitude</td>\n", | |
" <td class=\"iris-inclusion-cell\">-</td>\n", | |
" <td class=\"iris-inclusion-cell\">x</td>\n", | |
"</tr>\n", | |
"<tr class=\"iris\">\n", | |
" <td class=\"iris-title iris-word-cell\">Attributes</td>\n", | |
" <td class=\"iris-title\"></td>\n", | |
" <td class=\"iris-title\"></td>\n", | |
"</tr>\n", | |
"<tr class=\"iris\">\n", | |
" <td class=\"iris-word-cell iris-subheading-cell\">\tConventions</td>\n", | |
" <td class=\"iris-word-cell\" colspan=\"2\">'CF-1.7'</td>\n", | |
"</tr>\n", | |
"</table>\n", | |
" " | |
], | |
"text/plain": [ | |
"<iris 'Cube' of sample_grid / (unknown) (latitude: 180; longitude: 360)>" | |
] | |
}, | |
"execution_count": 48, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"iris.load_cube(src_file)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "1e2fcd00-3503-4ea4-a523-017dfe8ae8bb", | |
"metadata": {}, | |
"source": [ | |
"When multiple cubes are loaded, these warnings can end up duplicated. This is a bug." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"id": "a487a2ef-043a-4266-aeb3-40c1f42d359b", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/2985628163.py:2: FutureWarning: Ignoring a datum in netCDF load for consistency with existing behaviour. In a future version of Iris, this datum will be applied. To apply the datum when loading, use the iris.FUTURE.datum_support flag.\n", | |
" iris.load_cube(src_file)\n", | |
"/var/tmp/ipykernel_60451/2985628163.py:2: FutureWarning: Ignoring a datum in netCDF load for consistency with existing behaviour. In a future version of Iris, this datum will be applied. To apply the datum when loading, use the iris.FUTURE.datum_support flag.\n", | |
" iris.load_cube(src_file)\n" | |
] | |
} | |
], | |
"source": [ | |
"for _ in range(2):\n", | |
" iris.load_cube(src_file)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"id": "a3db8712-e638-4411-9532-8b6f8675c9a7", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import warnings" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "6f30ee28-5b08-446a-a221-91436ab109df", | |
"metadata": {}, | |
"source": [ | |
"Normally, warnings from the same source are grouped together and only raise one warning." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"id": "34b46453-7a9d-4cdb-a518-0c17ec58527e", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/1364601749.py:2: UserWarning: warned once\n", | |
" warnings.warn(\"warned once\")\n" | |
] | |
} | |
], | |
"source": [ | |
"for _ in range(2):\n", | |
" warnings.warn(\"warned once\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "a1580ff2-aa3d-4d0c-a07c-32c83ce648be", | |
"metadata": {}, | |
"source": [ | |
"Even when `warnings` is explicitly set to raise one warning, they are still duplicated." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"id": "48281a73-9d75-40da-9bfb-1d381a4ff285", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3734422316.py:4: FutureWarning: Ignoring a datum in netCDF load for consistency with existing behaviour. In a future version of Iris, this datum will be applied. To apply the datum when loading, use the iris.FUTURE.datum_support flag.\n", | |
" iris.load_cube(src_file)\n", | |
"/var/tmp/ipykernel_60451/3734422316.py:4: FutureWarning: Ignoring a datum in netCDF load for consistency with existing behaviour. In a future version of Iris, this datum will be applied. To apply the datum when loading, use the iris.FUTURE.datum_support flag.\n", | |
" iris.load_cube(src_file)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"once\")\n", | |
" for _ in range(2):\n", | |
" iris.load_cube(src_file)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"id": "4c21c0f1-5b89-4845-8e6c-8c5af6074c73", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/262650537.py:4: UserWarning: warned once\n", | |
" warnings.warn(\"warned once\")\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"once\")\n", | |
" for _ in range(2):\n", | |
" warnings.warn(\"warned once\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "e5e109f0-0aee-46b1-be8b-7c679ae0cc02", | |
"metadata": {}, | |
"source": [ | |
"### Replicating the Warning Duplication Bug\n", | |
"\n", | |
"We believe this is due to a known bug with the `warnings` module where warnings are repeated if a `catch_warnings` context manager is entered in between. See https://github.com/python/cpython/issues/73858" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"id": "aca04b4b-aa90-49be-9e25-902aff38f40b", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3930640416.py:2: UserWarning: warned twice\n", | |
" warnings.warn(\"warned twice\")\n", | |
"/var/tmp/ipykernel_60451/3930640416.py:2: UserWarning: warned twice\n", | |
" warnings.warn(\"warned twice\")\n" | |
] | |
} | |
], | |
"source": [ | |
"for _ in range(2):\n", | |
" warnings.warn(\"warned twice\")\n", | |
" with warnings.catch_warnings():\n", | |
" pass" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "0b9d46c6-8e04-48f9-9f63-892f052ce4d5", | |
"metadata": {}, | |
"source": [ | |
"This context manager can show up in many odd places: e.g. importing packages\n", | |
"\n", | |
"Notably, this happens with numpy and dask.array" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 32, | |
"id": "d69a0e52-b1b0-4748-b588-0efc46ebabb9", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3985990569.py:2: UserWarning: import warning\n", | |
" warnings.warn(\"import warning\")\n" | |
] | |
} | |
], | |
"source": [ | |
"for _ in range(3):\n", | |
" warnings.warn(\"import warning\")\n", | |
" import pandas" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "cc9f21bd-8b90-4d26-90eb-ed6d718d24ba", | |
"metadata": {}, | |
"source": [ | |
"---\n", | |
"### Duplication Bug Workarounds\n", | |
"\n", | |
"One way we can solve this problem by using the lru_cache decorator." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"id": "ea761aec-eaba-4275-be63-4b5350e89198", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from functools import lru_cache" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"id": "9462cdd1-0a6a-45f3-9086-5067125e9f08", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"once\n" | |
] | |
} | |
], | |
"source": [ | |
"@lru_cache(None)\n", | |
"def print_once(msg):\n", | |
" print(msg)\n", | |
"\n", | |
"for _ in range(2):\n", | |
" print_once(\"once\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 33, | |
"id": "b0d5f452-9de6-4c31-8eae-e42adbe60984", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"print_once(\"once\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 34, | |
"id": "f0e5df9c-9807-4fd8-9089-f3ca2d184444", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/27440559.py:3: UserWarning: warned once\n", | |
" warnings.warn(msg)\n" | |
] | |
} | |
], | |
"source": [ | |
"@lru_cache(None)\n", | |
"def warn_once(msg):\n", | |
" warnings.warn(msg)\n", | |
"\n", | |
"for _ in range(2):\n", | |
" warn_once(\"warned once\")\n", | |
" with warnings.catch_warnings():\n", | |
" pass" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "641a6eb1-d68e-4c91-8f76-bbdcc95cf953", | |
"metadata": {}, | |
"source": [ | |
"However, this comes at the expense of flexibility in choosing the frequency of warnings." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 35, | |
"id": "45241b17-5c6e-4ca1-9842-38c732d40029", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/2874389630.py:3: UserWarning: normal warning\n", | |
" warnings.warn(\"normal warning\")\n", | |
"/var/tmp/ipykernel_60451/2874389630.py:4: UserWarning: normal warning\n", | |
" warnings.warn(\"normal warning\")\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" warnings.warn(\"normal warning\")\n", | |
" warnings.warn(\"normal warning\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 36, | |
"id": "fedc97d7-18ce-4426-8834-50ee3dae7b83", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/27440559.py:3: UserWarning: cached warning\n", | |
" warnings.warn(msg)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" warn_once(\"cached warning\")\n", | |
" warn_once(\"cached warning\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "a88c6320-810f-4956-a45c-63785d21effc", | |
"metadata": {}, | |
"source": [ | |
"With a bit of work it's possible to replicate the behaviour of \"default\" with a similar warning function." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"id": "275d29ae-cd81-4e2c-9798-d081d0e0f2a2", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import traceback" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 37, | |
"id": "f564eb4f-fda3-4ae7-a589-9ad4435179d2", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/933927709.py:13: UserWarning: cached warning\n", | |
" warn_default(\"cached warning\", 1)\n", | |
"/var/tmp/ipykernel_60451/933927709.py:14: UserWarning: cached warning\n", | |
" warn_default(\"cached warning\", 1)\n" | |
] | |
} | |
], | |
"source": [ | |
"@lru_cache(None)\n", | |
"def warn_default_inner(msg, frame, stacklevel):\n", | |
" warnings.warn(msg, stacklevel=stacklevel)\n", | |
"\n", | |
"def warn_default(msg, stacklevel):\n", | |
" stacklevel += 1\n", | |
" stack = traceback.format_stack()\n", | |
" frame = stack[-stacklevel]\n", | |
" warn_default_inner(msg, frame, stacklevel + 1)\n", | |
"\n", | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" warn_default(\"cached warning\", 1)\n", | |
" warn_default(\"cached warning\", 1)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "80c20184-a83b-4c79-bc43-eb90a0e448cb", | |
"metadata": {}, | |
"source": [ | |
"This is flexible enough to allow stricter behaviour." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 38, | |
"id": "9b321ac7-63f4-41f9-89f0-93abf869b8a2", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3150170836.py:3: UserWarning: cached warning\n", | |
" warn_default(\"cached warning\", 1)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"once\")\n", | |
" warn_default(\"cached warning\", 1)\n", | |
" warn_default(\"cached warning\", 1)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "24ec60bc-2afc-4d50-854b-868e7d318dfb", | |
"metadata": {}, | |
"source": [ | |
"Though this is not flexible enough to fix bugs that force warnings to be stricter in a stricter context." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 39, | |
"id": "e1b6d33e-bdde-4ac2-94a8-927782aa2a82", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/1408376727.py:3: UserWarning: cached warning\n", | |
" warn_default(\"cached warning\", 1)\n", | |
"/var/tmp/ipykernel_60451/1408376727.py:6: UserWarning: cached warning\n", | |
" warn_default(\"cached warning\", 1)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"once\")\n", | |
" warn_default(\"cached warning\", 1)\n", | |
" with warnings.catch_warnings():\n", | |
" pass\n", | |
" warn_default(\"cached warning\", 1)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "1802f155-4eb1-46db-8488-601d836d1c71", | |
"metadata": {}, | |
"source": [ | |
"This is not flexible enough to allow more lenient behaviour in more lenient contexts" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"id": "bf5ba22e-e160-4e93-9b3b-5bf61d562226", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3639898056.py:4: UserWarning: cached warning\n", | |
" warn_default(\"cached warning\", stacklevel=1)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"always\")\n", | |
" for _ in range(2):\n", | |
" warn_default(\"cached warning\", stacklevel=1)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"id": "391ff050-e194-459c-85ac-54e7838ccd23", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/278831279.py:4: UserWarning: normal warning\n", | |
" warnings.warn(\"normal warning\", stacklevel=1)\n", | |
"/var/tmp/ipykernel_60451/278831279.py:4: UserWarning: normal warning\n", | |
" warnings.warn(\"normal warning\", stacklevel=1)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"always\")\n", | |
" for _ in range(2):\n", | |
" warnings.warn(\"normal warning\", stacklevel=1)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "c30c7a26-6c87-4cc6-a951-17aa4c9f7672", | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "c9529521-e3e9-4d98-a723-1e05e1281aed", | |
"metadata": {}, | |
"source": [ | |
"---\n", | |
"### What exactly is default behaviour?\n", | |
"\n", | |
"Default behaviour calls one warning _per line_ that called the warning." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"id": "b7ff82c4-4c56-47a5-b838-19efcc0c61a3", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/263019615.py:3: UserWarning: warn twice\n", | |
" warnings.warn(\"warn twice\")\n", | |
"/var/tmp/ipykernel_60451/263019615.py:4: UserWarning: warn twice\n", | |
" warnings.warn(\"warn twice\")\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" warnings.warn(\"warn twice\")\n", | |
" warnings.warn(\"warn twice\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 24, | |
"id": "a1b4af0f-9a16-4850-a5b4-107f27584374", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3794237510.py:4: UserWarning: warn once\n", | |
" warnings.warn(\"warn once\")\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" for _ in range(2):\n", | |
" warnings.warn(\"warn once\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "8f3cdc78-427d-4dc2-92dc-0f5bd2ce5b36", | |
"metadata": {}, | |
"source": [ | |
"Warnings have a stacklevel argument which allows the warning to be called lower down the call stack." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 25, | |
"id": "c71b4353-0485-4b56-b59d-492d7dfcd239", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/2884063885.py:4: UserWarning: warned by function\n", | |
" raise_warning()\n" | |
] | |
} | |
], | |
"source": [ | |
"def raise_warning(level=2):\n", | |
" warnings.warn(\"warned by function\", stacklevel=level)\n", | |
"\n", | |
"raise_warning()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "1a05e011-f0cb-4b9b-a95d-fb3423194bc4", | |
"metadata": {}, | |
"source": [ | |
"What matters to default behaviour is if the line _where the warning is raised_ is the same." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 26, | |
"id": "cf7e7b6e-91ea-44aa-affb-c18a543b558b", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/922400754.py:3: UserWarning: warned by function\n", | |
" raise_warning()\n", | |
"/var/tmp/ipykernel_60451/922400754.py:4: UserWarning: warned by function\n", | |
" raise_warning()\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" raise_warning()\n", | |
" raise_warning()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 27, | |
"id": "5ab696e0-7cc6-4b29-99da-30f4755bc365", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/2884063885.py:2: UserWarning: warned by function\n", | |
" warnings.warn(\"warned by function\", stacklevel=level)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" raise_warning(1)\n", | |
" raise_warning(1)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "deba21d6-ecba-402a-81cd-9eabc0ffbd9b", | |
"metadata": {}, | |
"source": [ | |
"We can demonstrate that as long as the lines where the warning is raised are the same, it doesn't even matter if _subsequent_ frames of the stack differ, default behaviour will still only raise one warning." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 28, | |
"id": "2110ce85-57a6-4212-beb2-367ade1ffe85", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3618860832.py:10: UserWarning: warned by case\n", | |
" raise_warning_case(case, 2)\n" | |
] | |
} | |
], | |
"source": [ | |
"def raise_warning_case(case, level):\n", | |
" if case:\n", | |
" warnings.warn(\"warned by case\", stacklevel=level)\n", | |
" else:\n", | |
" warnings.warn(\"warned by case\", stacklevel=level)\n", | |
"\n", | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" for case in (True, False):\n", | |
" raise_warning_case(case, 2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 29, | |
"id": "6ed1794d-477d-4b49-b9eb-d9d56c8144b2", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/3618860832.py:3: UserWarning: warned by case\n", | |
" warnings.warn(\"warned by case\", stacklevel=level)\n", | |
"/var/tmp/ipykernel_60451/3618860832.py:5: UserWarning: warned by case\n", | |
" warnings.warn(\"warned by case\", stacklevel=level)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" for case in (True, False):\n", | |
" raise_warning_case(case, 1)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "ab10ac0d-4e79-4a76-931d-c51a05b650b8", | |
"metadata": {}, | |
"source": [ | |
"This same propertyholds for the `warn_default` function we have created." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 40, | |
"id": "4f8327e1-53b7-4fd5-a13d-1a4235e2686c", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/55505891.py:10: UserWarning: warned by case default\n", | |
" raise_warning_case_default(case, 2)\n" | |
] | |
} | |
], | |
"source": [ | |
"def raise_warning_case_default(case, level):\n", | |
" if case:\n", | |
" warn_default(\"warned by case default\", stacklevel=level)\n", | |
" else:\n", | |
" warn_default(\"warned by case default\", stacklevel=level)\n", | |
"\n", | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" for case in (True, False):\n", | |
" raise_warning_case_default(case, 2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 41, | |
"id": "48269ab0-5fc3-47c9-8486-bf5bc5c9a2aa", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/tmp/ipykernel_60451/55505891.py:3: UserWarning: warned by case default\n", | |
" warn_default(\"warned by case default\", stacklevel=level)\n", | |
"/var/tmp/ipykernel_60451/55505891.py:5: UserWarning: warned by case default\n", | |
" warn_default(\"warned by case default\", stacklevel=level)\n" | |
] | |
} | |
], | |
"source": [ | |
"with warnings.catch_warnings():\n", | |
" warnings.simplefilter(\"default\")\n", | |
" for case in (True, False):\n", | |
" raise_warning_case_default(case, 1)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "9a1a13d7-10f2-491b-894d-75f8cb88a898", | |
"metadata": {}, | |
"source": [ | |
"---\n", | |
"### Conclusion\n", | |
"\n", | |
"There are two alternate functions we could use to replace the regular warning call; one where we force \"default\" behaviour and one where we force \"once\" behaviour. The table below describes how flexible each solution would be at handling other contexts.\n", | |
"\n", | |
"|Method|Handles \"once\"|Handles \"default\"|Handles \"always\"\n", | |
"|:---|:---|:---|:---|\n", | |
"|Regular|sometimes|sometimes|always|\n", | |
"|Forced default|sometimes|always|never|\n", | |
"|Forced once|always|never|never|\n", | |
"\n", | |
"### Actions\n", | |
"\n", | |
"- Replace calls in iris to `warnings.catch_warnings()`.\n", | |
"- Replace calls to `warnings.warn` with more robust functions (decision needed)." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "420b225f-6364-4f97-bc1e-ef4e56cb85ef", | |
"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.9.17" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 5 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment