@wendellresearch-ai/benchwarmers 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +152 -147
- package/BENCHMARKS.md +262 -262
- package/GATEWAY.md +415 -272
- package/NOTICE +28 -28
- package/PRIVACY.md +46 -46
- package/README.md +408 -314
- package/SECURITY.md +83 -83
- package/TERMS.md +22 -22
- package/USAGE.md +186 -163
- package/VERSION +1 -1
- package/bin/benchwarmers.js +16 -74
- package/cli.py +674 -0
- package/examples/config/gateway.json +5 -5
- package/examples/config/model-roles.json +11 -11
- package/gateway.py +939 -755
- package/launcher.py +120 -0
- package/mcp_server.py +266 -266
- package/metrics/alerts.py +116 -116
- package/metrics/aliases.py +41 -41
- package/metrics/bench_collections.py +141 -141
- package/metrics/catalog.py +304 -295
- package/metrics/client.py +804 -394
- package/metrics/cliproxy.py +191 -191
- package/metrics/connect.py +691 -691
- package/metrics/cost.py +171 -152
- package/metrics/decide.py +227 -227
- package/metrics/discover.py +318 -318
- package/metrics/endpoints.py +436 -436
- package/metrics/formats.py +1021 -0
- package/metrics/guard.py +647 -592
- package/metrics/learn.py +234 -221
- package/metrics/ledger.py +148 -0
- package/metrics/litellm_hub.py +206 -206
- package/metrics/model_roles.py +94 -84
- package/metrics/offload.py +166 -166
- package/metrics/owui.py +205 -205
- package/metrics/pacing.py +248 -0
- package/metrics/paths.py +60 -60
- package/metrics/quota.py +383 -0
- package/metrics/route.py +581 -579
- package/metrics/scheduler.py +275 -275
- package/metrics/sources.py +167 -167
- package/metrics/wrong.py +144 -144
- package/package.json +69 -65
- package/perf/README.md +89 -89
- package/perf/run.py +284 -261
- package/scripts/auto_retire.py +367 -367
- package/scripts/check.py +113 -106
- package/scripts/check_deprecations.py +378 -378
- package/scripts/check_themes.py +103 -103
- package/scripts/init.py +124 -124
- package/scripts/list_served.py +78 -78
- package/scripts/notice.py +78 -78
- package/scripts/onboard.py +410 -331
- package/scripts/provider_tags.py +129 -129
- package/scripts/reprefix.py +136 -136
- package/scripts/sync_config.py +105 -105
- package/scripts/test_auth.py +255 -255
- package/scripts/test_cli.py +189 -0
- package/scripts/test_client.py +277 -233
- package/scripts/test_connect.py +222 -222
- package/scripts/test_first_run.py +180 -180
- package/scripts/test_formats.py +549 -0
- package/scripts/test_hubs.py +328 -328
- package/scripts/test_launcher.py +67 -0
- package/scripts/test_llm_log.py +85 -81
- package/scripts/test_mcp.py +178 -178
- package/scripts/test_merged.py +215 -214
- package/scripts/test_no_owui.py +291 -291
- package/scripts/test_owui.py +90 -90
- package/scripts/test_quota.py +334 -0
- package/scripts/test_serve_edit.py +453 -438
- package/scripts/test_server_json.py +79 -0
- package/scripts/test_verdict.py +102 -98
- package/scripts/test_vision.py +231 -228
- package/serve.py +3972 -3764
- package/suite/mine.py +154 -154
- package/suite/pace.py +145 -145
- package/suite/run.py +1046 -1042
- package/suite/seed.py +421 -421
- package/suite/tasks/claim-alias-unbound/fixtures/onboard.py +286 -286
- package/suite/tasks/claim-error-text-string/fixtures/decide.py +187 -187
- package/suite/tasks/claim-list-body/fixtures/gateway.py +235 -235
- package/suite/tasks/claim-member-nominated-twice/fixtures/gateway.py +284 -284
- package/suite/tasks/claim-nominee-uses-slot/fixtures/gateway.py +284 -284
- package/suite/tasks/claim-silent-exit/fixtures/gateway.py +235 -235
- package/suite/tasks/claim-sse-hang/fixtures/gateway.py +235 -235
- package/suite/tasks/claim-unknown-nominee-crash/fixtures/gateway.py +284 -284
- package/suite/tasks/rebench-matchms-809-bug/task.json +23 -23
- package/suite/tasks/rebench-matchms-809-control/task.json +27 -27
- package/suite/tasks/rebench-more-itertools-1028-bug/task.json +23 -23
- package/suite/tasks/rebench-more-itertools-1028-control/task.json +27 -27
- package/suite/tasks/rebench-narwhals-2864-bug/task.json +23 -23
- package/suite/tasks/rebench-narwhals-2864-control/task.json +27 -27
- package/suite/tasks/rebench-quantecon-py-769-bug/task.json +23 -23
- package/suite/tasks/rebench-quantecon-py-769-control/task.json +27 -27
- package/suite/tasks/rebench-scrapy-6867-bug/task.json +23 -23
- package/suite/tasks/rebench-scrapy-6867-control/task.json +27 -27
- package/ui/bench.css +430 -425
- package/ui/bench.js +1757 -1576
- package/ui/themes/dark.css +35 -35
- package/ui/themes/hardwood.css +52 -52
- package/ui/themes/rainforest.css +32 -32
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"shape": "rebench",
|
|
3
|
-
"source": "matchms__matchms-809",
|
|
4
|
-
"upstream": "matchms/matchms",
|
|
5
|
-
"source_url": "https://github.com/matchms/matchms/pull/809",
|
|
6
|
-
"created": "2025-06-13 09:19:05",
|
|
7
|
-
"license": "Apache-2.0",
|
|
8
|
-
"score_in": "first_line",
|
|
9
|
-
"min_answer_chars": 8,
|
|
10
|
-
"id": "rebench-matchms-809-bug",
|
|
11
|
-
"title": "Real bug: name the line a later fix changed",
|
|
12
|
-
"why": "matchms/matchms PR #809, created 2025-06-13 09:19:05: https://github.com/matchms/matchms/pull/809\nThe fix in matchms/importing/load_from_msp.py (base 0b1707bd86) changed line(s) 112:\n - tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)\", peak)\n + tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:[eE][-+]?\\d+)?)\", peak)\nProblem: matchms fails when reading spectra where abundance is in scientific notation Example spectrum - spotted in the MSDial EI RI library. Funny thing is our regex only handles lower case `e` notation while this uses upper case. Makes me think if we shouldn't just leave the parsing of stuff to python and \nCheck the fix is the bug, and visible from this file alone, before removing draft.",
|
|
13
|
-
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file.\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 1| import re\n 2| from typing import Generator, List, Tuple\n 3| import numpy as np\n 4| from matchms.importing.parsing_utils import parse_spectrum_dict\n 5| from matchms.Spectrum import Spectrum\n 6| \n 7| \n 8| def load_from_msp(filename: str, metadata_harmonization: bool = True) -> Generator[Spectrum, None, None]:\n 9| \"\"\"\n 10| MSP file to a :py:class:`~matchms.Spectrum.Spectrum` objects\n 11| Function that reads a .msp file and converts the info\n 12| in :py:class:`~matchms.Spectrum.Spectrum` objects.\n 13| \n 14| Parameters\n 15| ----------\n 16| filename:\n 17| Path of the msp file.\n 18| metadata_harmonization : bool, optional\n 19| Set to False if metadata harmonization to default keys is not desired.\n 20| The default is True.\n 21| \n 22| Yields\n 23| ------\n 24| Yield a spectrum object with the data of the msp file\n 25| \n 26| \n 27| Example:\n 28| \n 29| .. code-block:: python\n 30| \n 31| from matchms.importing import load_from_msp\n 32| \n 33| # Download msp file from MassBank of North America repository at https://mona.fiehnlab.ucdavis.edu/\n 34| file_msp = \"MoNA-export-GC-MS-first10.msp\"\n 35| spectra = list(load_from_msp(file_msp))\n 36| \"\"\"\n 37| for spectrum in parse_msp_file(filename):\n 38| yield parse_spectrum_dict(spectrum=spectrum, metadata_harmonization=metadata_harmonization, spectrum_type=\"own\")\n 39| \n 40| \n 41| def parse_msp_file(filename: str) -> Generator[dict, None, None]:\n 42| \"\"\"Read msp file and parse info in List of spectrum dictionaries.\"\"\"\n 43| \n 44| # Lists/dicts that will contain all params, masses and intensities of each molecule\n 45| params = {}\n 46| masses = np.array([])\n 47| intensities = np.array([])\n 48| peak_comments = {}\n 49| \n 50| # Peaks counter. Used to track and count the number of peaks\n 51| peakscount = 0\n 52| \n 53| with open(filename, \"r\", encoding=\"utf-8\", errors=\"ignore\") as f:\n 54| for line in f:\n 55| rline = line.rstrip()\n 56| \n 57| if len(rline) == 0:\n 58| continue\n 59| \n 60| if contains_metadata(rline):\n 61| parse_metadata(rline, params)\n 62| continue\n 63| \n 64| mz, ints, comment = _parse_line_with_peaks(rline)\n 65| \n 66| masses = np.append(masses, mz)\n 67| intensities = np.append(intensities, ints)\n 68| \n 69| if comment is not None:\n 70| peak_comments.update({float(masses[-1]): comment})\n 71| \n 72| peakscount += len(mz)\n 73| \n 74| # Obtaining the masses and intensities\n 75| if int(params[\"num peaks\"]) == peakscount:\n 76| peakscount = 0\n 77| # Handles edge cases with GOLM files where the nominal mass is written with a comma instead of a dot\n 78| nominal_mass = params.get(\"mw\")\n 79| if nominal_mass and isinstance(nominal_mass, str):\n 80| params[\"mw\"] = nominal_mass.replace(\",\", \".\")\n 81| \n 82| yield {\n 83| \"params\": (params),\n 84| \"m/z array\": masses,\n 85| \"intensity array\": intensities,\n 86| \"peak comments\": peak_comments,\n 87| }\n 88| \n 89| params = {}\n 90| masses = []\n 91| intensities = []\n 92| peak_comments = {}\n 93| \n 94| \n 95| def _parse_line_with_peaks(rline: str) -> Tuple[List[float], List[float], str]:\n 96| \"\"\"Parse a line containing peaks consisting of mz and intensity values with optional comments.\n 97| \n 98| Args:\n 99| rline (str): Line with peaks read from the MSP.\n100| \n101| Returns:\n102| Tuple[List[float], List[float], str]: mz, intensity and peak comments obtained from the line.\n103| \"\"\"\n104| comment, rline = get_peak_comment(rline)\n105| mz, intensities = get_peak_values(rline)\n106| \n107| return mz, intensities, comment\n108| \n109| \n110| def get_peak_values(peak: str) -> Tuple[List[float], List[float]]:\n111| \"\"\"Get the m/z and intensity value from the line containing the peak information.\"\"\"\n112| tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)\", peak)\n113| if len(tokens) % 2 != 0:\n114| raise RuntimeError(\"Wrong peak format detected!\")\n115| \n116| tokens = list(map(float, tokens))\n117| mz = tokens[0::2]\n118| intensities = tokens[1::2]\n119| return mz, intensities\n120| \n121| \n122| def get_peak_comment(rline: str) -> Tuple[str, str]:\n123| \"\"\"Get the peak comment from the line containing the peak information.\"\"\"\n124| try:\n125| comment = re.findall(r\"[\\\"\\'](.*)[\\\"\\']\", rline)[0]\n126| rline = rline[: rline.index('\"')]\n127| except IndexError:\n128| comment = None\n129| return comment, rline\n130| \n131| \n132| def parse_metadata(rline: str, params: dict):\n133| \"\"\"Reads metadata contained in line into params dict.\n134| \n135| The complexity of this function stems from the fact that MSP allows for many different formats of metadata.\n136| \n137| Parameters\n138| ----------\n139| rline: str\n140| The line of the read MSP file that contains metadata.\n141| params : dict\n142| The params that the key value pairs of the metadata line will be added to.\n143| \"\"\"\n144| splitted_line = rline.split(\":\", 1)\n145| if len(splitted_line) != 2:\n146| return\n147| \n148| key, value = splitted_line[0].strip().lower(), splitted_line[1].strip()\n149| \n150| if key == \"comments\" and \"=\" in value:\n151| _parse_comments(value, params)\n152| elif key == \"synon\" and rline.count(\":\") >= 2:\n153| _parse_synon(rline, params)\n154| else:\n155| # Fallback for generic key: value pairs\n156| params[key] = value\n157| \n158| \n159| def _parse_comments(value: str, params: dict):\n160| \"\"\"Parses key-value pairs from comments line into params.\"\"\"\n161| value = value.replace(\"'\", '\"') # Normalize quotes\n162| pattern = (\n163| r'(\\S+)=\"([^\"]*)\"|'\n164| r'\"(\\w+)=([^\"]*)\"|'\n165| r'\"([^\"]*)=([^\"]*)\"|'\n166| r\"(\\S+)=(\\d+(?:\\.\\d*)?)\"\n167| )\n168| for match in re.findall(pattern, value):\n169| match = [i for i in match if i]\n170| if len(match) == 2:\n171| m_key, m_value = match\n172| m_key = m_key.strip().lower()\n173| m_value = m_value.strip()\n174| if m_key == \"smiles\" and m_key in params:\n175| params[f\"{m_key}_2\"] = m_value\n176| else:\n177| params[m_key] = m_value\n178| \n179| \n180| def _parse_synon(rline: str, params: dict):\n181| \"\"\"Parses synon lines with multiple colons.\"\"\"\n182| parts = rline.split(\":\", 2)\n183| synon_key = f\"{parts[0].strip().lower()}: {parts[1].strip().lower()}\"\n184| synon_value = parts[2].strip().replace(\",\", \".\")\n185| if synon_key == \"synon: metb n\":\n186| params.setdefault(synon_key, []).append(synon_value)\n187| else:\n188| params[synon_key] = synon_value\n189| \n190| \n191| def contains_metadata(rline: str) -> bool:\n192| \"\"\"Check if line contains Spectrum metadata.\"\"\"\n193| has_colon = \":\" in rline\n194| return has_colon and not _is_golm_peak_format(rline)\n195| \n196| \n197| def _is_golm_peak_format(rline: str) -> bool:\n198| \"\"\"This function detects whether a line is a line containing peaks in the GOLM MSP format.\n199| \n200| The GOLM MSP format encodes peaks as mz:intensity - this resembles a metadata line, but actually contains peaks.\n201| It is therefore necessary to explicitly check this corner case when determining whether a line is peaks or metadata.\n202| \n203| Args:\n204| rline (str): Line to check whether it contains peaks from GOLM\n205| \n206| Returns:\n207| bool: Whether the line is a line with peaks from GOLM or not.\n208| \"\"\"\n209| return re.match(r\"(\\d+:{1}\\d+)\", rline) is not None",
|
|
14
|
-
"must_find": [
|
|
15
|
-
{
|
|
16
|
-
"regex": "^\\W*fault:\\s*line\\s*(?:112)\\b",
|
|
17
|
-
"label": "fault: line 112"
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
"must_not_claim": [
|
|
21
|
-
"no fault"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"shape": "rebench",
|
|
3
|
+
"source": "matchms__matchms-809",
|
|
4
|
+
"upstream": "matchms/matchms",
|
|
5
|
+
"source_url": "https://github.com/matchms/matchms/pull/809",
|
|
6
|
+
"created": "2025-06-13 09:19:05",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"score_in": "first_line",
|
|
9
|
+
"min_answer_chars": 8,
|
|
10
|
+
"id": "rebench-matchms-809-bug",
|
|
11
|
+
"title": "Real bug: name the line a later fix changed",
|
|
12
|
+
"why": "matchms/matchms PR #809, created 2025-06-13 09:19:05: https://github.com/matchms/matchms/pull/809\nThe fix in matchms/importing/load_from_msp.py (base 0b1707bd86) changed line(s) 112:\n - tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)\", peak)\n + tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:[eE][-+]?\\d+)?)\", peak)\nProblem: matchms fails when reading spectra where abundance is in scientific notation Example spectrum - spotted in the MSDial EI RI library. Funny thing is our regex only handles lower case `e` notation while this uses upper case. Makes me think if we shouldn't just leave the parsing of stuff to python and \nCheck the fix is the bug, and visible from this file alone, before removing draft.",
|
|
13
|
+
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file.\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 1| import re\n 2| from typing import Generator, List, Tuple\n 3| import numpy as np\n 4| from matchms.importing.parsing_utils import parse_spectrum_dict\n 5| from matchms.Spectrum import Spectrum\n 6| \n 7| \n 8| def load_from_msp(filename: str, metadata_harmonization: bool = True) -> Generator[Spectrum, None, None]:\n 9| \"\"\"\n 10| MSP file to a :py:class:`~matchms.Spectrum.Spectrum` objects\n 11| Function that reads a .msp file and converts the info\n 12| in :py:class:`~matchms.Spectrum.Spectrum` objects.\n 13| \n 14| Parameters\n 15| ----------\n 16| filename:\n 17| Path of the msp file.\n 18| metadata_harmonization : bool, optional\n 19| Set to False if metadata harmonization to default keys is not desired.\n 20| The default is True.\n 21| \n 22| Yields\n 23| ------\n 24| Yield a spectrum object with the data of the msp file\n 25| \n 26| \n 27| Example:\n 28| \n 29| .. code-block:: python\n 30| \n 31| from matchms.importing import load_from_msp\n 32| \n 33| # Download msp file from MassBank of North America repository at https://mona.fiehnlab.ucdavis.edu/\n 34| file_msp = \"MoNA-export-GC-MS-first10.msp\"\n 35| spectra = list(load_from_msp(file_msp))\n 36| \"\"\"\n 37| for spectrum in parse_msp_file(filename):\n 38| yield parse_spectrum_dict(spectrum=spectrum, metadata_harmonization=metadata_harmonization, spectrum_type=\"own\")\n 39| \n 40| \n 41| def parse_msp_file(filename: str) -> Generator[dict, None, None]:\n 42| \"\"\"Read msp file and parse info in List of spectrum dictionaries.\"\"\"\n 43| \n 44| # Lists/dicts that will contain all params, masses and intensities of each molecule\n 45| params = {}\n 46| masses = np.array([])\n 47| intensities = np.array([])\n 48| peak_comments = {}\n 49| \n 50| # Peaks counter. Used to track and count the number of peaks\n 51| peakscount = 0\n 52| \n 53| with open(filename, \"r\", encoding=\"utf-8\", errors=\"ignore\") as f:\n 54| for line in f:\n 55| rline = line.rstrip()\n 56| \n 57| if len(rline) == 0:\n 58| continue\n 59| \n 60| if contains_metadata(rline):\n 61| parse_metadata(rline, params)\n 62| continue\n 63| \n 64| mz, ints, comment = _parse_line_with_peaks(rline)\n 65| \n 66| masses = np.append(masses, mz)\n 67| intensities = np.append(intensities, ints)\n 68| \n 69| if comment is not None:\n 70| peak_comments.update({float(masses[-1]): comment})\n 71| \n 72| peakscount += len(mz)\n 73| \n 74| # Obtaining the masses and intensities\n 75| if int(params[\"num peaks\"]) == peakscount:\n 76| peakscount = 0\n 77| # Handles edge cases with GOLM files where the nominal mass is written with a comma instead of a dot\n 78| nominal_mass = params.get(\"mw\")\n 79| if nominal_mass and isinstance(nominal_mass, str):\n 80| params[\"mw\"] = nominal_mass.replace(\",\", \".\")\n 81| \n 82| yield {\n 83| \"params\": (params),\n 84| \"m/z array\": masses,\n 85| \"intensity array\": intensities,\n 86| \"peak comments\": peak_comments,\n 87| }\n 88| \n 89| params = {}\n 90| masses = []\n 91| intensities = []\n 92| peak_comments = {}\n 93| \n 94| \n 95| def _parse_line_with_peaks(rline: str) -> Tuple[List[float], List[float], str]:\n 96| \"\"\"Parse a line containing peaks consisting of mz and intensity values with optional comments.\n 97| \n 98| Args:\n 99| rline (str): Line with peaks read from the MSP.\n100| \n101| Returns:\n102| Tuple[List[float], List[float], str]: mz, intensity and peak comments obtained from the line.\n103| \"\"\"\n104| comment, rline = get_peak_comment(rline)\n105| mz, intensities = get_peak_values(rline)\n106| \n107| return mz, intensities, comment\n108| \n109| \n110| def get_peak_values(peak: str) -> Tuple[List[float], List[float]]:\n111| \"\"\"Get the m/z and intensity value from the line containing the peak information.\"\"\"\n112| tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?)\", peak)\n113| if len(tokens) % 2 != 0:\n114| raise RuntimeError(\"Wrong peak format detected!\")\n115| \n116| tokens = list(map(float, tokens))\n117| mz = tokens[0::2]\n118| intensities = tokens[1::2]\n119| return mz, intensities\n120| \n121| \n122| def get_peak_comment(rline: str) -> Tuple[str, str]:\n123| \"\"\"Get the peak comment from the line containing the peak information.\"\"\"\n124| try:\n125| comment = re.findall(r\"[\\\"\\'](.*)[\\\"\\']\", rline)[0]\n126| rline = rline[: rline.index('\"')]\n127| except IndexError:\n128| comment = None\n129| return comment, rline\n130| \n131| \n132| def parse_metadata(rline: str, params: dict):\n133| \"\"\"Reads metadata contained in line into params dict.\n134| \n135| The complexity of this function stems from the fact that MSP allows for many different formats of metadata.\n136| \n137| Parameters\n138| ----------\n139| rline: str\n140| The line of the read MSP file that contains metadata.\n141| params : dict\n142| The params that the key value pairs of the metadata line will be added to.\n143| \"\"\"\n144| splitted_line = rline.split(\":\", 1)\n145| if len(splitted_line) != 2:\n146| return\n147| \n148| key, value = splitted_line[0].strip().lower(), splitted_line[1].strip()\n149| \n150| if key == \"comments\" and \"=\" in value:\n151| _parse_comments(value, params)\n152| elif key == \"synon\" and rline.count(\":\") >= 2:\n153| _parse_synon(rline, params)\n154| else:\n155| # Fallback for generic key: value pairs\n156| params[key] = value\n157| \n158| \n159| def _parse_comments(value: str, params: dict):\n160| \"\"\"Parses key-value pairs from comments line into params.\"\"\"\n161| value = value.replace(\"'\", '\"') # Normalize quotes\n162| pattern = (\n163| r'(\\S+)=\"([^\"]*)\"|'\n164| r'\"(\\w+)=([^\"]*)\"|'\n165| r'\"([^\"]*)=([^\"]*)\"|'\n166| r\"(\\S+)=(\\d+(?:\\.\\d*)?)\"\n167| )\n168| for match in re.findall(pattern, value):\n169| match = [i for i in match if i]\n170| if len(match) == 2:\n171| m_key, m_value = match\n172| m_key = m_key.strip().lower()\n173| m_value = m_value.strip()\n174| if m_key == \"smiles\" and m_key in params:\n175| params[f\"{m_key}_2\"] = m_value\n176| else:\n177| params[m_key] = m_value\n178| \n179| \n180| def _parse_synon(rline: str, params: dict):\n181| \"\"\"Parses synon lines with multiple colons.\"\"\"\n182| parts = rline.split(\":\", 2)\n183| synon_key = f\"{parts[0].strip().lower()}: {parts[1].strip().lower()}\"\n184| synon_value = parts[2].strip().replace(\",\", \".\")\n185| if synon_key == \"synon: metb n\":\n186| params.setdefault(synon_key, []).append(synon_value)\n187| else:\n188| params[synon_key] = synon_value\n189| \n190| \n191| def contains_metadata(rline: str) -> bool:\n192| \"\"\"Check if line contains Spectrum metadata.\"\"\"\n193| has_colon = \":\" in rline\n194| return has_colon and not _is_golm_peak_format(rline)\n195| \n196| \n197| def _is_golm_peak_format(rline: str) -> bool:\n198| \"\"\"This function detects whether a line is a line containing peaks in the GOLM MSP format.\n199| \n200| The GOLM MSP format encodes peaks as mz:intensity - this resembles a metadata line, but actually contains peaks.\n201| It is therefore necessary to explicitly check this corner case when determining whether a line is peaks or metadata.\n202| \n203| Args:\n204| rline (str): Line to check whether it contains peaks from GOLM\n205| \n206| Returns:\n207| bool: Whether the line is a line with peaks from GOLM or not.\n208| \"\"\"\n209| return re.match(r\"(\\d+:{1}\\d+)\", rline) is not None",
|
|
14
|
+
"must_find": [
|
|
15
|
+
{
|
|
16
|
+
"regex": "^\\W*fault:\\s*line\\s*(?:112)\\b",
|
|
17
|
+
"label": "fault: line 112"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"must_not_claim": [
|
|
21
|
+
"no fault"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"shape": "rebench",
|
|
3
|
-
"source": "matchms__matchms-809",
|
|
4
|
-
"upstream": "matchms/matchms",
|
|
5
|
-
"source_url": "https://github.com/matchms/matchms/pull/809",
|
|
6
|
-
"created": "2025-06-13 09:19:05",
|
|
7
|
-
"license": "Apache-2.0",
|
|
8
|
-
"score_in": "first_line",
|
|
9
|
-
"min_answer_chars": 8,
|
|
10
|
-
"id": "rebench-matchms-809-control",
|
|
11
|
-
"title": "Real-bug control: say NO FAULT",
|
|
12
|
-
"why": "matchms/importing/load_from_msp.py after the fix in https://github.com/matchms/matchms/pull/809; the paired bug task is the file before it. The answer is NO FAULT.",
|
|
13
|
-
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file.\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 1| import re\n 2| from typing import Generator, List, Tuple\n 3| import numpy as np\n 4| from matchms.importing.parsing_utils import parse_spectrum_dict\n 5| from matchms.Spectrum import Spectrum\n 6| \n 7| \n 8| def load_from_msp(filename: str, metadata_harmonization: bool = True) -> Generator[Spectrum, None, None]:\n 9| \"\"\"\n 10| MSP file to a :py:class:`~matchms.Spectrum.Spectrum` objects\n 11| Function that reads a .msp file and converts the info\n 12| in :py:class:`~matchms.Spectrum.Spectrum` objects.\n 13| \n 14| Parameters\n 15| ----------\n 16| filename:\n 17| Path of the msp file.\n 18| metadata_harmonization : bool, optional\n 19| Set to False if metadata harmonization to default keys is not desired.\n 20| The default is True.\n 21| \n 22| Yields\n 23| ------\n 24| Yield a spectrum object with the data of the msp file\n 25| \n 26| \n 27| Example:\n 28| \n 29| .. code-block:: python\n 30| \n 31| from matchms.importing import load_from_msp\n 32| \n 33| # Download msp file from MassBank of North America repository at https://mona.fiehnlab.ucdavis.edu/\n 34| file_msp = \"MoNA-export-GC-MS-first10.msp\"\n 35| spectra = list(load_from_msp(file_msp))\n 36| \"\"\"\n 37| for spectrum in parse_msp_file(filename):\n 38| yield parse_spectrum_dict(spectrum=spectrum, metadata_harmonization=metadata_harmonization, spectrum_type=\"own\")\n 39| \n 40| \n 41| def parse_msp_file(filename: str) -> Generator[dict, None, None]:\n 42| \"\"\"Read msp file and parse info in List of spectrum dictionaries.\"\"\"\n 43| \n 44| # Lists/dicts that will contain all params, masses and intensities of each molecule\n 45| params = {}\n 46| masses = np.array([])\n 47| intensities = np.array([])\n 48| peak_comments = {}\n 49| \n 50| # Peaks counter. Used to track and count the number of peaks\n 51| peakscount = 0\n 52| \n 53| with open(filename, \"r\", encoding=\"utf-8\", errors=\"ignore\") as f:\n 54| for line in f:\n 55| rline = line.rstrip()\n 56| \n 57| if len(rline) == 0:\n 58| continue\n 59| \n 60| if contains_metadata(rline):\n 61| parse_metadata(rline, params)\n 62| continue\n 63| \n 64| mz, ints, comment = _parse_line_with_peaks(rline)\n 65| \n 66| masses = np.append(masses, mz)\n 67| intensities = np.append(intensities, ints)\n 68| \n 69| if comment is not None:\n 70| peak_comments.update({float(masses[-1]): comment})\n 71| \n 72| peakscount += len(mz)\n 73| \n 74| # Obtaining the masses and intensities\n 75| if int(params[\"num peaks\"]) == peakscount:\n 76| peakscount = 0\n 77| # Handles edge cases with GOLM files where the nominal mass is written with a comma instead of a dot\n 78| nominal_mass = params.get(\"mw\")\n 79| if nominal_mass and isinstance(nominal_mass, str):\n 80| params[\"mw\"] = nominal_mass.replace(\",\", \".\")\n 81| \n 82| yield {\n 83| \"params\": (params),\n 84| \"m/z array\": masses,\n 85| \"intensity array\": intensities,\n 86| \"peak comments\": peak_comments,\n 87| }\n 88| \n 89| params = {}\n 90| masses = []\n 91| intensities = []\n 92| peak_comments = {}\n 93| \n 94| \n 95| def _parse_line_with_peaks(rline: str) -> Tuple[List[float], List[float], str]:\n 96| \"\"\"Parse a line containing peaks consisting of mz and intensity values with optional comments.\n 97| \n 98| Args:\n 99| rline (str): Line with peaks read from the MSP.\n100| \n101| Returns:\n102| Tuple[List[float], List[float], str]: mz, intensity and peak comments obtained from the line.\n103| \"\"\"\n104| comment, rline = get_peak_comment(rline)\n105| mz, intensities = get_peak_values(rline)\n106| \n107| return mz, intensities, comment\n108| \n109| \n110| def get_peak_values(peak: str) -> Tuple[List[float], List[float]]:\n111| \"\"\"Get the m/z and intensity value from the line containing the peak information.\"\"\"\n112| tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:[eE][-+]?\\d+)?)\", peak)\n113| if len(tokens) % 2 != 0:\n114| raise RuntimeError(\"Wrong peak format detected!\")\n115| \n116| tokens = list(map(float, tokens))\n117| mz = tokens[0::2]\n118| intensities = tokens[1::2]\n119| return mz, intensities\n120| \n121| \n122| def get_peak_comment(rline: str) -> Tuple[str, str]:\n123| \"\"\"Get the peak comment from the line containing the peak information.\"\"\"\n124| try:\n125| comment = re.findall(r\"[\\\"\\'](.*)[\\\"\\']\", rline)[0]\n126| rline = rline[: rline.index('\"')]\n127| except IndexError:\n128| comment = None\n129| return comment, rline\n130| \n131| \n132| def parse_metadata(rline: str, params: dict):\n133| \"\"\"Reads metadata contained in line into params dict.\n134| \n135| The complexity of this function stems from the fact that MSP allows for many different formats of metadata.\n136| \n137| Parameters\n138| ----------\n139| rline: str\n140| The line of the read MSP file that contains metadata.\n141| params : dict\n142| The params that the key value pairs of the metadata line will be added to.\n143| \"\"\"\n144| splitted_line = rline.split(\":\", 1)\n145| if len(splitted_line) != 2:\n146| return\n147| \n148| key, value = splitted_line[0].strip().lower(), splitted_line[1].strip()\n149| \n150| if key == \"comments\" and \"=\" in value:\n151| _parse_comments(value, params)\n152| elif key == \"synon\" and rline.count(\":\") >= 2:\n153| _parse_synon(rline, params)\n154| else:\n155| # Fallback for generic key: value pairs\n156| params[key] = value\n157| \n158| \n159| def _parse_comments(value: str, params: dict):\n160| \"\"\"Parses key-value pairs from comments line into params.\"\"\"\n161| value = value.replace(\"'\", '\"') # Normalize quotes\n162| pattern = (\n163| r'(\\S+)=\"([^\"]*)\"|'\n164| r'\"(\\w+)=([^\"]*)\"|'\n165| r'\"([^\"]*)=([^\"]*)\"|'\n166| r\"(\\S+)=(\\d+(?:\\.\\d*)?)\"\n167| )\n168| for match in re.findall(pattern, value):\n169| match = [i for i in match if i]\n170| if len(match) == 2:\n171| m_key, m_value = match\n172| m_key = m_key.strip().lower()\n173| m_value = m_value.strip()\n174| if m_key == \"smiles\" and m_key in params:\n175| params[f\"{m_key}_2\"] = m_value\n176| else:\n177| params[m_key] = m_value\n178| \n179| \n180| def _parse_synon(rline: str, params: dict):\n181| \"\"\"Parses synon lines with multiple colons.\"\"\"\n182| parts = rline.split(\":\", 2)\n183| synon_key = f\"{parts[0].strip().lower()}: {parts[1].strip().lower()}\"\n184| synon_value = parts[2].strip().replace(\",\", \".\")\n185| if synon_key == \"synon: metb n\":\n186| params.setdefault(synon_key, []).append(synon_value)\n187| else:\n188| params[synon_key] = synon_value\n189| \n190| \n191| def contains_metadata(rline: str) -> bool:\n192| \"\"\"Check if line contains Spectrum metadata.\"\"\"\n193| has_colon = \":\" in rline\n194| return has_colon and not _is_golm_peak_format(rline)\n195| \n196| \n197| def _is_golm_peak_format(rline: str) -> bool:\n198| \"\"\"This function detects whether a line is a line containing peaks in the GOLM MSP format.\n199| \n200| The GOLM MSP format encodes peaks as mz:intensity - this resembles a metadata line, but actually contains peaks.\n201| It is therefore necessary to explicitly check this corner case when determining whether a line is peaks or metadata.\n202| \n203| Args:\n204| rline (str): Line to check whether it contains peaks from GOLM\n205| \n206| Returns:\n207| bool: Whether the line is a line with peaks from GOLM or not.\n208| \"\"\"\n209| return re.match(r\"(\\d+:{1}\\d+)\", rline) is not None",
|
|
14
|
-
"must_find": [
|
|
15
|
-
{
|
|
16
|
-
"any_of": [
|
|
17
|
-
"no fault"
|
|
18
|
-
]
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"must_not_claim": [
|
|
22
|
-
{
|
|
23
|
-
"regex": "^\\W*fault:\\s*line",
|
|
24
|
-
"label": "fault: line"
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"shape": "rebench",
|
|
3
|
+
"source": "matchms__matchms-809",
|
|
4
|
+
"upstream": "matchms/matchms",
|
|
5
|
+
"source_url": "https://github.com/matchms/matchms/pull/809",
|
|
6
|
+
"created": "2025-06-13 09:19:05",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"score_in": "first_line",
|
|
9
|
+
"min_answer_chars": 8,
|
|
10
|
+
"id": "rebench-matchms-809-control",
|
|
11
|
+
"title": "Real-bug control: say NO FAULT",
|
|
12
|
+
"why": "matchms/importing/load_from_msp.py after the fix in https://github.com/matchms/matchms/pull/809; the paired bug task is the file before it. The answer is NO FAULT.",
|
|
13
|
+
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file.\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 1| import re\n 2| from typing import Generator, List, Tuple\n 3| import numpy as np\n 4| from matchms.importing.parsing_utils import parse_spectrum_dict\n 5| from matchms.Spectrum import Spectrum\n 6| \n 7| \n 8| def load_from_msp(filename: str, metadata_harmonization: bool = True) -> Generator[Spectrum, None, None]:\n 9| \"\"\"\n 10| MSP file to a :py:class:`~matchms.Spectrum.Spectrum` objects\n 11| Function that reads a .msp file and converts the info\n 12| in :py:class:`~matchms.Spectrum.Spectrum` objects.\n 13| \n 14| Parameters\n 15| ----------\n 16| filename:\n 17| Path of the msp file.\n 18| metadata_harmonization : bool, optional\n 19| Set to False if metadata harmonization to default keys is not desired.\n 20| The default is True.\n 21| \n 22| Yields\n 23| ------\n 24| Yield a spectrum object with the data of the msp file\n 25| \n 26| \n 27| Example:\n 28| \n 29| .. code-block:: python\n 30| \n 31| from matchms.importing import load_from_msp\n 32| \n 33| # Download msp file from MassBank of North America repository at https://mona.fiehnlab.ucdavis.edu/\n 34| file_msp = \"MoNA-export-GC-MS-first10.msp\"\n 35| spectra = list(load_from_msp(file_msp))\n 36| \"\"\"\n 37| for spectrum in parse_msp_file(filename):\n 38| yield parse_spectrum_dict(spectrum=spectrum, metadata_harmonization=metadata_harmonization, spectrum_type=\"own\")\n 39| \n 40| \n 41| def parse_msp_file(filename: str) -> Generator[dict, None, None]:\n 42| \"\"\"Read msp file and parse info in List of spectrum dictionaries.\"\"\"\n 43| \n 44| # Lists/dicts that will contain all params, masses and intensities of each molecule\n 45| params = {}\n 46| masses = np.array([])\n 47| intensities = np.array([])\n 48| peak_comments = {}\n 49| \n 50| # Peaks counter. Used to track and count the number of peaks\n 51| peakscount = 0\n 52| \n 53| with open(filename, \"r\", encoding=\"utf-8\", errors=\"ignore\") as f:\n 54| for line in f:\n 55| rline = line.rstrip()\n 56| \n 57| if len(rline) == 0:\n 58| continue\n 59| \n 60| if contains_metadata(rline):\n 61| parse_metadata(rline, params)\n 62| continue\n 63| \n 64| mz, ints, comment = _parse_line_with_peaks(rline)\n 65| \n 66| masses = np.append(masses, mz)\n 67| intensities = np.append(intensities, ints)\n 68| \n 69| if comment is not None:\n 70| peak_comments.update({float(masses[-1]): comment})\n 71| \n 72| peakscount += len(mz)\n 73| \n 74| # Obtaining the masses and intensities\n 75| if int(params[\"num peaks\"]) == peakscount:\n 76| peakscount = 0\n 77| # Handles edge cases with GOLM files where the nominal mass is written with a comma instead of a dot\n 78| nominal_mass = params.get(\"mw\")\n 79| if nominal_mass and isinstance(nominal_mass, str):\n 80| params[\"mw\"] = nominal_mass.replace(\",\", \".\")\n 81| \n 82| yield {\n 83| \"params\": (params),\n 84| \"m/z array\": masses,\n 85| \"intensity array\": intensities,\n 86| \"peak comments\": peak_comments,\n 87| }\n 88| \n 89| params = {}\n 90| masses = []\n 91| intensities = []\n 92| peak_comments = {}\n 93| \n 94| \n 95| def _parse_line_with_peaks(rline: str) -> Tuple[List[float], List[float], str]:\n 96| \"\"\"Parse a line containing peaks consisting of mz and intensity values with optional comments.\n 97| \n 98| Args:\n 99| rline (str): Line with peaks read from the MSP.\n100| \n101| Returns:\n102| Tuple[List[float], List[float], str]: mz, intensity and peak comments obtained from the line.\n103| \"\"\"\n104| comment, rline = get_peak_comment(rline)\n105| mz, intensities = get_peak_values(rline)\n106| \n107| return mz, intensities, comment\n108| \n109| \n110| def get_peak_values(peak: str) -> Tuple[List[float], List[float]]:\n111| \"\"\"Get the m/z and intensity value from the line containing the peak information.\"\"\"\n112| tokens = re.findall(r\"(\\d+(?:\\.\\d+)?(?:[eE][-+]?\\d+)?)\", peak)\n113| if len(tokens) % 2 != 0:\n114| raise RuntimeError(\"Wrong peak format detected!\")\n115| \n116| tokens = list(map(float, tokens))\n117| mz = tokens[0::2]\n118| intensities = tokens[1::2]\n119| return mz, intensities\n120| \n121| \n122| def get_peak_comment(rline: str) -> Tuple[str, str]:\n123| \"\"\"Get the peak comment from the line containing the peak information.\"\"\"\n124| try:\n125| comment = re.findall(r\"[\\\"\\'](.*)[\\\"\\']\", rline)[0]\n126| rline = rline[: rline.index('\"')]\n127| except IndexError:\n128| comment = None\n129| return comment, rline\n130| \n131| \n132| def parse_metadata(rline: str, params: dict):\n133| \"\"\"Reads metadata contained in line into params dict.\n134| \n135| The complexity of this function stems from the fact that MSP allows for many different formats of metadata.\n136| \n137| Parameters\n138| ----------\n139| rline: str\n140| The line of the read MSP file that contains metadata.\n141| params : dict\n142| The params that the key value pairs of the metadata line will be added to.\n143| \"\"\"\n144| splitted_line = rline.split(\":\", 1)\n145| if len(splitted_line) != 2:\n146| return\n147| \n148| key, value = splitted_line[0].strip().lower(), splitted_line[1].strip()\n149| \n150| if key == \"comments\" and \"=\" in value:\n151| _parse_comments(value, params)\n152| elif key == \"synon\" and rline.count(\":\") >= 2:\n153| _parse_synon(rline, params)\n154| else:\n155| # Fallback for generic key: value pairs\n156| params[key] = value\n157| \n158| \n159| def _parse_comments(value: str, params: dict):\n160| \"\"\"Parses key-value pairs from comments line into params.\"\"\"\n161| value = value.replace(\"'\", '\"') # Normalize quotes\n162| pattern = (\n163| r'(\\S+)=\"([^\"]*)\"|'\n164| r'\"(\\w+)=([^\"]*)\"|'\n165| r'\"([^\"]*)=([^\"]*)\"|'\n166| r\"(\\S+)=(\\d+(?:\\.\\d*)?)\"\n167| )\n168| for match in re.findall(pattern, value):\n169| match = [i for i in match if i]\n170| if len(match) == 2:\n171| m_key, m_value = match\n172| m_key = m_key.strip().lower()\n173| m_value = m_value.strip()\n174| if m_key == \"smiles\" and m_key in params:\n175| params[f\"{m_key}_2\"] = m_value\n176| else:\n177| params[m_key] = m_value\n178| \n179| \n180| def _parse_synon(rline: str, params: dict):\n181| \"\"\"Parses synon lines with multiple colons.\"\"\"\n182| parts = rline.split(\":\", 2)\n183| synon_key = f\"{parts[0].strip().lower()}: {parts[1].strip().lower()}\"\n184| synon_value = parts[2].strip().replace(\",\", \".\")\n185| if synon_key == \"synon: metb n\":\n186| params.setdefault(synon_key, []).append(synon_value)\n187| else:\n188| params[synon_key] = synon_value\n189| \n190| \n191| def contains_metadata(rline: str) -> bool:\n192| \"\"\"Check if line contains Spectrum metadata.\"\"\"\n193| has_colon = \":\" in rline\n194| return has_colon and not _is_golm_peak_format(rline)\n195| \n196| \n197| def _is_golm_peak_format(rline: str) -> bool:\n198| \"\"\"This function detects whether a line is a line containing peaks in the GOLM MSP format.\n199| \n200| The GOLM MSP format encodes peaks as mz:intensity - this resembles a metadata line, but actually contains peaks.\n201| It is therefore necessary to explicitly check this corner case when determining whether a line is peaks or metadata.\n202| \n203| Args:\n204| rline (str): Line to check whether it contains peaks from GOLM\n205| \n206| Returns:\n207| bool: Whether the line is a line with peaks from GOLM or not.\n208| \"\"\"\n209| return re.match(r\"(\\d+:{1}\\d+)\", rline) is not None",
|
|
14
|
+
"must_find": [
|
|
15
|
+
{
|
|
16
|
+
"any_of": [
|
|
17
|
+
"no fault"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"must_not_claim": [
|
|
22
|
+
{
|
|
23
|
+
"regex": "^\\W*fault:\\s*line",
|
|
24
|
+
"label": "fault: line"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"shape": "rebench",
|
|
3
|
-
"source": "more-itertools__more-itertools-1028",
|
|
4
|
-
"upstream": "more-itertools/more-itertools",
|
|
5
|
-
"source_url": "https://github.com/more-itertools/more-itertools/pull/1028",
|
|
6
|
-
"created": "2025-07-14 00:35:41",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"score_in": "first_line",
|
|
9
|
-
"min_answer_chars": 8,
|
|
10
|
-
"id": "rebench-more-itertools-1028-bug",
|
|
11
|
-
"title": "Real bug: name the line a later fix changed",
|
|
12
|
-
"why": "more-itertools/more-itertools PR #1028, created 2025-07-14 00:35:41: https://github.com/more-itertools/more-itertools/pull/1028\nThe fix in more_itertools/more.py (base c834d6e4a0) changed line(s) 286:\n - if hasattr(iterable, '__reversed__'):\n + if getattr(iterable, '__reversed__', None):\nProblem: last() fails if __reversed__ is None, which is the case for the Mapping abc Using `last()` on this class: ``` from collections.abc import Mapping from more_itertools import last class MyMapping(Mapping): def __getitem__(self, key): return 1 def __iter__(self): return iter([1]) def __len__(self): ret\nCheck the fix is the bug, and visible from this file alone, before removing draft.",
|
|
13
|
-
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file (an excerpt: lines 86-485).\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 86| 'distinct_combinations',\n 87| 'distinct_permutations',\n 88| 'distribute',\n 89| 'divide',\n 90| 'doublestarmap',\n 91| 'duplicates_everseen',\n 92| 'duplicates_justseen',\n 93| 'classify_unique',\n 94| 'exactly_n',\n 95| 'filter_except',\n 96| 'filter_map',\n 97| 'first',\n 98| 'gray_product',\n 99| 'groupby_transform',\n100| 'ichunked',\n101| 'iequals',\n102| 'idft',\n103| 'ilen',\n104| 'interleave',\n105| 'interleave_evenly',\n106| 'interleave_longest',\n107| 'intersperse',\n108| 'is_sorted',\n109| 'islice_extended',\n110| 'iterate',\n111| 'iter_suppress',\n112| 'join_mappings',\n113| 'last',\n114| 'locate',\n115| 'longest_common_prefix',\n116| 'lstrip',\n117| 'make_decorator',\n118| 'map_except',\n119| 'map_if',\n120| 'map_reduce',\n121| 'mark_ends',\n122| 'minmax',\n123| 'nth_or_last',\n124| 'nth_permutation',\n125| 'nth_prime',\n126| 'nth_product',\n127| 'nth_combination_with_replacement',\n128| 'numeric_range',\n129| 'one',\n130| 'only',\n131| 'outer_product',\n132| 'padded',\n133| 'partial_product',\n134| 'partitions',\n135| 'peekable',\n136| 'permutation_index',\n137| 'powerset_of_sets',\n138| 'product_index',\n139| 'raise_',\n140| 'repeat_each',\n141| 'repeat_last',\n142| 'replace',\n143| 'rlocate',\n144| 'rstrip',\n145| 'run_length',\n146| 'sample',\n147| 'seekable',\n148| 'set_partitions',\n149| 'side_effect',\n150| 'sliced',\n151| 'sort_together',\n152| 'split_after',\n153| 'split_at',\n154| 'split_before',\n155| 'split_into',\n156| 'split_when',\n157| 'spy',\n158| 'stagger',\n159| 'strip',\n160| 'strictly_n',\n161| 'substrings',\n162| 'substrings_indexes',\n163| 'takewhile_inclusive',\n164| 'time_limited',\n165| 'unique_in_window',\n166| 'unique_to_each',\n167| 'unzip',\n168| 'value_chain',\n169| 'windowed',\n170| 'windowed_complete',\n171| 'with_iter',\n172| 'zip_broadcast',\n173| 'zip_equal',\n174| 'zip_offset',\n175| ]\n176| \n177| # math.sumprod is available for Python 3.12+\n178| try:\n179| from math import sumprod as _fsumprod\n180| \n181| except ImportError: # pragma: no cover\n182| # Extended precision algorithms from T. J. Dekker,\n183| # \"A Floating-Point Technique for Extending the Available Precision\"\n184| # https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf\n185| # Formulas: (5.5) (5.6) and (5.8). Code: mul12()\n186| \n187| def dl_split(x: float):\n188| \"Split a float into two half-precision components.\"\n189| t = x * 134217729.0 # Veltkamp constant = 2.0 ** 27 + 1\n190| hi = t - (t - x)\n191| lo = x - hi\n192| return hi, lo\n193| \n194| def dl_mul(x, y):\n195| \"Lossless multiplication.\"\n196| xx_hi, xx_lo = dl_split(x)\n197| yy_hi, yy_lo = dl_split(y)\n198| p = xx_hi * yy_hi\n199| q = xx_hi * yy_lo + xx_lo * yy_hi\n200| z = p + q\n201| zz = p - z + q + xx_lo * yy_lo\n202| return z, zz\n203| \n204| def _fsumprod(p, q):\n205| return fsum(chain.from_iterable(map(dl_mul, p, q)))\n206| \n207| \n208| def chunked(iterable, n, strict=False):\n209| \"\"\"Break *iterable* into lists of length *n*:\n210| \n211| >>> list(chunked([1, 2, 3, 4, 5, 6], 3))\n212| [[1, 2, 3], [4, 5, 6]]\n213| \n214| By the default, the last yielded list will have fewer than *n* elements\n215| if the length of *iterable* is not divisible by *n*:\n216| \n217| >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3))\n218| [[1, 2, 3], [4, 5, 6], [7, 8]]\n219| \n220| To use a fill-in value instead, see the :func:`grouper` recipe.\n221| \n222| If the length of *iterable* is not divisible by *n* and *strict* is\n223| ``True``, then ``ValueError`` will be raised before the last\n224| list is yielded.\n225| \n226| \"\"\"\n227| iterator = iter(partial(take, n, iter(iterable)), [])\n228| if strict:\n229| if n is None:\n230| raise ValueError('n must not be None when using strict mode.')\n231| \n232| def ret():\n233| for chunk in iterator:\n234| if len(chunk) != n:\n235| raise ValueError('iterable is not divisible by n.')\n236| yield chunk\n237| \n238| return ret()\n239| else:\n240| return iterator\n241| \n242| \n243| def first(iterable, default=_marker):\n244| \"\"\"Return the first item of *iterable*, or *default* if *iterable* is\n245| empty.\n246| \n247| >>> first([0, 1, 2, 3])\n248| 0\n249| >>> first([], 'some default')\n250| 'some default'\n251| \n252| If *default* is not provided and there are no items in the iterable,\n253| raise ``ValueError``.\n254| \n255| :func:`first` is useful when you have a generator of expensive-to-retrieve\n256| values and want any arbitrary one. It is marginally shorter than\n257| ``next(iter(iterable), default)``.\n258| \n259| \"\"\"\n260| for item in iterable:\n261| return item\n262| if default is _marker:\n263| raise ValueError(\n264| 'first() was called on an empty iterable, '\n265| 'and no default value was provided.'\n266| )\n267| return default\n268| \n269| \n270| def last(iterable, default=_marker):\n271| \"\"\"Return the last item of *iterable*, or *default* if *iterable* is\n272| empty.\n273| \n274| >>> last([0, 1, 2, 3])\n275| 3\n276| >>> last([], 'some default')\n277| 'some default'\n278| \n279| If *default* is not provided and there are no items in the iterable,\n280| raise ``ValueError``.\n281| \"\"\"\n282| try:\n283| if isinstance(iterable, Sequence):\n284| return iterable[-1]\n285| # Work around https://bugs.python.org/issue38525\n286| if hasattr(iterable, '__reversed__'):\n287| return next(reversed(iterable))\n288| return deque(iterable, maxlen=1)[-1]\n289| except (IndexError, TypeError, StopIteration):\n290| if default is _marker:\n291| raise ValueError(\n292| 'last() was called on an empty iterable, '\n293| 'and no default value was provided.'\n294| )\n295| return default\n296| \n297| \n298| def nth_or_last(iterable, n, default=_marker):\n299| \"\"\"Return the nth or the last item of *iterable*,\n300| or *default* if *iterable* is empty.\n301| \n302| >>> nth_or_last([0, 1, 2, 3], 2)\n303| 2\n304| >>> nth_or_last([0, 1], 2)\n305| 1\n306| >>> nth_or_last([], 0, 'some default')\n307| 'some default'\n308| \n309| If *default* is not provided and there are no items in the iterable,\n310| raise ``ValueError``.\n311| \"\"\"\n312| return last(islice(iterable, n + 1), default=default)\n313| \n314| \n315| class peekable:\n316| \"\"\"Wrap an iterator to allow lookahead and prepending elements.\n317| \n318| Call :meth:`peek` on the result to get the value that will be returned\n319| by :func:`next`. This won't advance the iterator:\n320| \n321| >>> p = peekable(['a', 'b'])\n322| >>> p.peek()\n323| 'a'\n324| >>> next(p)\n325| 'a'\n326| \n327| Pass :meth:`peek` a default value to return that instead of raising\n328| ``StopIteration`` when the iterator is exhausted.\n329| \n330| >>> p = peekable([])\n331| >>> p.peek('hi')\n332| 'hi'\n333| \n334| peekables also offer a :meth:`prepend` method, which \"inserts\" items\n335| at the head of the iterable:\n336| \n337| >>> p = peekable([1, 2, 3])\n338| >>> p.prepend(10, 11, 12)\n339| >>> next(p)\n340| 10\n341| >>> p.peek()\n342| 11\n343| >>> list(p)\n344| [11, 12, 1, 2, 3]\n345| \n346| peekables can be indexed. Index 0 is the item that will be returned by\n347| :func:`next`, index 1 is the item after that, and so on:\n348| The values up to the given index will be cached.\n349| \n350| >>> p = peekable(['a', 'b', 'c', 'd'])\n351| >>> p[0]\n352| 'a'\n353| >>> p[1]\n354| 'b'\n355| >>> next(p)\n356| 'a'\n357| \n358| Negative indexes are supported, but be aware that they will cache the\n359| remaining items in the source iterator, which may require significant\n360| storage.\n361| \n362| To check whether a peekable is exhausted, check its truth value:\n363| \n364| >>> p = peekable(['a', 'b'])\n365| >>> if p: # peekable has items\n366| ... list(p)\n367| ['a', 'b']\n368| >>> if not p: # peekable is exhausted\n369| ... list(p)\n370| []\n371| \n372| \"\"\"\n373| \n374| def __init__(self, iterable):\n375| self._it = iter(iterable)\n376| self._cache = deque()\n377| \n378| def __iter__(self):\n379| return self\n380| \n381| def __bool__(self):\n382| try:\n383| self.peek()\n384| except StopIteration:\n385| return False\n386| return True\n387| \n388| def peek(self, default=_marker):\n389| \"\"\"Return the item that will be next returned from ``next()``.\n390| \n391| Return ``default`` if there are no items left. If ``default`` is not\n392| provided, raise ``StopIteration``.\n393| \n394| \"\"\"\n395| if not self._cache:\n396| try:\n397| self._cache.append(next(self._it))\n398| except StopIteration:\n399| if default is _marker:\n400| raise\n401| return default\n402| return self._cache[0]\n403| \n404| def prepend(self, *items):\n405| \"\"\"Stack up items to be the next ones returned from ``next()`` or\n406| ``self.peek()``. The items will be returned in\n407| first in, first out order::\n408| \n409| >>> p = peekable([1, 2, 3])\n410| >>> p.prepend(10, 11, 12)\n411| >>> next(p)\n412| 10\n413| >>> list(p)\n414| [11, 12, 1, 2, 3]\n415| \n416| It is possible, by prepending items, to \"resurrect\" a peekable that\n417| previously raised ``StopIteration``.\n418| \n419| >>> p = peekable([])\n420| >>> next(p)\n421| Traceback (most recent call last):\n422| ...\n423| StopIteration\n424| >>> p.prepend(1)\n425| >>> next(p)\n426| 1\n427| >>> next(p)\n428| Traceback (most recent call last):\n429| ...\n430| StopIteration\n431| \n432| \"\"\"\n433| self._cache.extendleft(reversed(items))\n434| \n435| def __next__(self):\n436| if self._cache:\n437| return self._cache.popleft()\n438| \n439| return next(self._it)\n440| \n441| def _get_slice(self, index):\n442| # Normalize the slice's arguments\n443| step = 1 if (index.step is None) else index.step\n444| if step > 0:\n445| start = 0 if (index.start is None) else index.start\n446| stop = maxsize if (index.stop is None) else index.stop\n447| elif step < 0:\n448| start = -1 if (index.start is None) else index.start\n449| stop = (-maxsize - 1) if (index.stop is None) else index.stop\n450| else:\n451| raise ValueError('slice step cannot be zero')\n452| \n453| # If either the start or stop index is negative, we'll need to cache\n454| # the rest of the iterable in order to slice from the right side.\n455| if (start < 0) or (stop < 0):\n456| self._cache.extend(self._it)\n457| # Otherwise we'll need to find the rightmost index and cache to that\n458| # point.\n459| else:\n460| n = min(max(start, stop) + 1, maxsize)\n461| cache_len = len(self._cache)\n462| if n >= cache_len:\n463| self._cache.extend(islice(self._it, n - cache_len))\n464| \n465| return list(self._cache)[index]\n466| \n467| def __getitem__(self, index):\n468| if isinstance(index, slice):\n469| return self._get_slice(index)\n470| \n471| cache_len = len(self._cache)\n472| if index < 0:\n473| self._cache.extend(self._it)\n474| elif index >= cache_len:\n475| self._cache.extend(islice(self._it, index + 1 - cache_len))\n476| \n477| return self._cache[index]\n478| \n479| \n480| def consumer(func):\n481| \"\"\"Decorator that automatically advances a PEP-342-style \"reverse iterator\"\n482| to its first yield point so you don't have to call ``next()`` on it\n483| manually.\n484| \n485| >>> @consumer",
|
|
14
|
-
"must_find": [
|
|
15
|
-
{
|
|
16
|
-
"regex": "^\\W*fault:\\s*line\\s*(?:286)\\b",
|
|
17
|
-
"label": "fault: line 286"
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
"must_not_claim": [
|
|
21
|
-
"no fault"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"shape": "rebench",
|
|
3
|
+
"source": "more-itertools__more-itertools-1028",
|
|
4
|
+
"upstream": "more-itertools/more-itertools",
|
|
5
|
+
"source_url": "https://github.com/more-itertools/more-itertools/pull/1028",
|
|
6
|
+
"created": "2025-07-14 00:35:41",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"score_in": "first_line",
|
|
9
|
+
"min_answer_chars": 8,
|
|
10
|
+
"id": "rebench-more-itertools-1028-bug",
|
|
11
|
+
"title": "Real bug: name the line a later fix changed",
|
|
12
|
+
"why": "more-itertools/more-itertools PR #1028, created 2025-07-14 00:35:41: https://github.com/more-itertools/more-itertools/pull/1028\nThe fix in more_itertools/more.py (base c834d6e4a0) changed line(s) 286:\n - if hasattr(iterable, '__reversed__'):\n + if getattr(iterable, '__reversed__', None):\nProblem: last() fails if __reversed__ is None, which is the case for the Mapping abc Using `last()` on this class: ``` from collections.abc import Mapping from more_itertools import last class MyMapping(Mapping): def __getitem__(self, key): return 1 def __iter__(self): return iter([1]) def __len__(self): ret\nCheck the fix is the bug, and visible from this file alone, before removing draft.",
|
|
13
|
+
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file (an excerpt: lines 86-485).\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 86| 'distinct_combinations',\n 87| 'distinct_permutations',\n 88| 'distribute',\n 89| 'divide',\n 90| 'doublestarmap',\n 91| 'duplicates_everseen',\n 92| 'duplicates_justseen',\n 93| 'classify_unique',\n 94| 'exactly_n',\n 95| 'filter_except',\n 96| 'filter_map',\n 97| 'first',\n 98| 'gray_product',\n 99| 'groupby_transform',\n100| 'ichunked',\n101| 'iequals',\n102| 'idft',\n103| 'ilen',\n104| 'interleave',\n105| 'interleave_evenly',\n106| 'interleave_longest',\n107| 'intersperse',\n108| 'is_sorted',\n109| 'islice_extended',\n110| 'iterate',\n111| 'iter_suppress',\n112| 'join_mappings',\n113| 'last',\n114| 'locate',\n115| 'longest_common_prefix',\n116| 'lstrip',\n117| 'make_decorator',\n118| 'map_except',\n119| 'map_if',\n120| 'map_reduce',\n121| 'mark_ends',\n122| 'minmax',\n123| 'nth_or_last',\n124| 'nth_permutation',\n125| 'nth_prime',\n126| 'nth_product',\n127| 'nth_combination_with_replacement',\n128| 'numeric_range',\n129| 'one',\n130| 'only',\n131| 'outer_product',\n132| 'padded',\n133| 'partial_product',\n134| 'partitions',\n135| 'peekable',\n136| 'permutation_index',\n137| 'powerset_of_sets',\n138| 'product_index',\n139| 'raise_',\n140| 'repeat_each',\n141| 'repeat_last',\n142| 'replace',\n143| 'rlocate',\n144| 'rstrip',\n145| 'run_length',\n146| 'sample',\n147| 'seekable',\n148| 'set_partitions',\n149| 'side_effect',\n150| 'sliced',\n151| 'sort_together',\n152| 'split_after',\n153| 'split_at',\n154| 'split_before',\n155| 'split_into',\n156| 'split_when',\n157| 'spy',\n158| 'stagger',\n159| 'strip',\n160| 'strictly_n',\n161| 'substrings',\n162| 'substrings_indexes',\n163| 'takewhile_inclusive',\n164| 'time_limited',\n165| 'unique_in_window',\n166| 'unique_to_each',\n167| 'unzip',\n168| 'value_chain',\n169| 'windowed',\n170| 'windowed_complete',\n171| 'with_iter',\n172| 'zip_broadcast',\n173| 'zip_equal',\n174| 'zip_offset',\n175| ]\n176| \n177| # math.sumprod is available for Python 3.12+\n178| try:\n179| from math import sumprod as _fsumprod\n180| \n181| except ImportError: # pragma: no cover\n182| # Extended precision algorithms from T. J. Dekker,\n183| # \"A Floating-Point Technique for Extending the Available Precision\"\n184| # https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf\n185| # Formulas: (5.5) (5.6) and (5.8). Code: mul12()\n186| \n187| def dl_split(x: float):\n188| \"Split a float into two half-precision components.\"\n189| t = x * 134217729.0 # Veltkamp constant = 2.0 ** 27 + 1\n190| hi = t - (t - x)\n191| lo = x - hi\n192| return hi, lo\n193| \n194| def dl_mul(x, y):\n195| \"Lossless multiplication.\"\n196| xx_hi, xx_lo = dl_split(x)\n197| yy_hi, yy_lo = dl_split(y)\n198| p = xx_hi * yy_hi\n199| q = xx_hi * yy_lo + xx_lo * yy_hi\n200| z = p + q\n201| zz = p - z + q + xx_lo * yy_lo\n202| return z, zz\n203| \n204| def _fsumprod(p, q):\n205| return fsum(chain.from_iterable(map(dl_mul, p, q)))\n206| \n207| \n208| def chunked(iterable, n, strict=False):\n209| \"\"\"Break *iterable* into lists of length *n*:\n210| \n211| >>> list(chunked([1, 2, 3, 4, 5, 6], 3))\n212| [[1, 2, 3], [4, 5, 6]]\n213| \n214| By the default, the last yielded list will have fewer than *n* elements\n215| if the length of *iterable* is not divisible by *n*:\n216| \n217| >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3))\n218| [[1, 2, 3], [4, 5, 6], [7, 8]]\n219| \n220| To use a fill-in value instead, see the :func:`grouper` recipe.\n221| \n222| If the length of *iterable* is not divisible by *n* and *strict* is\n223| ``True``, then ``ValueError`` will be raised before the last\n224| list is yielded.\n225| \n226| \"\"\"\n227| iterator = iter(partial(take, n, iter(iterable)), [])\n228| if strict:\n229| if n is None:\n230| raise ValueError('n must not be None when using strict mode.')\n231| \n232| def ret():\n233| for chunk in iterator:\n234| if len(chunk) != n:\n235| raise ValueError('iterable is not divisible by n.')\n236| yield chunk\n237| \n238| return ret()\n239| else:\n240| return iterator\n241| \n242| \n243| def first(iterable, default=_marker):\n244| \"\"\"Return the first item of *iterable*, or *default* if *iterable* is\n245| empty.\n246| \n247| >>> first([0, 1, 2, 3])\n248| 0\n249| >>> first([], 'some default')\n250| 'some default'\n251| \n252| If *default* is not provided and there are no items in the iterable,\n253| raise ``ValueError``.\n254| \n255| :func:`first` is useful when you have a generator of expensive-to-retrieve\n256| values and want any arbitrary one. It is marginally shorter than\n257| ``next(iter(iterable), default)``.\n258| \n259| \"\"\"\n260| for item in iterable:\n261| return item\n262| if default is _marker:\n263| raise ValueError(\n264| 'first() was called on an empty iterable, '\n265| 'and no default value was provided.'\n266| )\n267| return default\n268| \n269| \n270| def last(iterable, default=_marker):\n271| \"\"\"Return the last item of *iterable*, or *default* if *iterable* is\n272| empty.\n273| \n274| >>> last([0, 1, 2, 3])\n275| 3\n276| >>> last([], 'some default')\n277| 'some default'\n278| \n279| If *default* is not provided and there are no items in the iterable,\n280| raise ``ValueError``.\n281| \"\"\"\n282| try:\n283| if isinstance(iterable, Sequence):\n284| return iterable[-1]\n285| # Work around https://bugs.python.org/issue38525\n286| if hasattr(iterable, '__reversed__'):\n287| return next(reversed(iterable))\n288| return deque(iterable, maxlen=1)[-1]\n289| except (IndexError, TypeError, StopIteration):\n290| if default is _marker:\n291| raise ValueError(\n292| 'last() was called on an empty iterable, '\n293| 'and no default value was provided.'\n294| )\n295| return default\n296| \n297| \n298| def nth_or_last(iterable, n, default=_marker):\n299| \"\"\"Return the nth or the last item of *iterable*,\n300| or *default* if *iterable* is empty.\n301| \n302| >>> nth_or_last([0, 1, 2, 3], 2)\n303| 2\n304| >>> nth_or_last([0, 1], 2)\n305| 1\n306| >>> nth_or_last([], 0, 'some default')\n307| 'some default'\n308| \n309| If *default* is not provided and there are no items in the iterable,\n310| raise ``ValueError``.\n311| \"\"\"\n312| return last(islice(iterable, n + 1), default=default)\n313| \n314| \n315| class peekable:\n316| \"\"\"Wrap an iterator to allow lookahead and prepending elements.\n317| \n318| Call :meth:`peek` on the result to get the value that will be returned\n319| by :func:`next`. This won't advance the iterator:\n320| \n321| >>> p = peekable(['a', 'b'])\n322| >>> p.peek()\n323| 'a'\n324| >>> next(p)\n325| 'a'\n326| \n327| Pass :meth:`peek` a default value to return that instead of raising\n328| ``StopIteration`` when the iterator is exhausted.\n329| \n330| >>> p = peekable([])\n331| >>> p.peek('hi')\n332| 'hi'\n333| \n334| peekables also offer a :meth:`prepend` method, which \"inserts\" items\n335| at the head of the iterable:\n336| \n337| >>> p = peekable([1, 2, 3])\n338| >>> p.prepend(10, 11, 12)\n339| >>> next(p)\n340| 10\n341| >>> p.peek()\n342| 11\n343| >>> list(p)\n344| [11, 12, 1, 2, 3]\n345| \n346| peekables can be indexed. Index 0 is the item that will be returned by\n347| :func:`next`, index 1 is the item after that, and so on:\n348| The values up to the given index will be cached.\n349| \n350| >>> p = peekable(['a', 'b', 'c', 'd'])\n351| >>> p[0]\n352| 'a'\n353| >>> p[1]\n354| 'b'\n355| >>> next(p)\n356| 'a'\n357| \n358| Negative indexes are supported, but be aware that they will cache the\n359| remaining items in the source iterator, which may require significant\n360| storage.\n361| \n362| To check whether a peekable is exhausted, check its truth value:\n363| \n364| >>> p = peekable(['a', 'b'])\n365| >>> if p: # peekable has items\n366| ... list(p)\n367| ['a', 'b']\n368| >>> if not p: # peekable is exhausted\n369| ... list(p)\n370| []\n371| \n372| \"\"\"\n373| \n374| def __init__(self, iterable):\n375| self._it = iter(iterable)\n376| self._cache = deque()\n377| \n378| def __iter__(self):\n379| return self\n380| \n381| def __bool__(self):\n382| try:\n383| self.peek()\n384| except StopIteration:\n385| return False\n386| return True\n387| \n388| def peek(self, default=_marker):\n389| \"\"\"Return the item that will be next returned from ``next()``.\n390| \n391| Return ``default`` if there are no items left. If ``default`` is not\n392| provided, raise ``StopIteration``.\n393| \n394| \"\"\"\n395| if not self._cache:\n396| try:\n397| self._cache.append(next(self._it))\n398| except StopIteration:\n399| if default is _marker:\n400| raise\n401| return default\n402| return self._cache[0]\n403| \n404| def prepend(self, *items):\n405| \"\"\"Stack up items to be the next ones returned from ``next()`` or\n406| ``self.peek()``. The items will be returned in\n407| first in, first out order::\n408| \n409| >>> p = peekable([1, 2, 3])\n410| >>> p.prepend(10, 11, 12)\n411| >>> next(p)\n412| 10\n413| >>> list(p)\n414| [11, 12, 1, 2, 3]\n415| \n416| It is possible, by prepending items, to \"resurrect\" a peekable that\n417| previously raised ``StopIteration``.\n418| \n419| >>> p = peekable([])\n420| >>> next(p)\n421| Traceback (most recent call last):\n422| ...\n423| StopIteration\n424| >>> p.prepend(1)\n425| >>> next(p)\n426| 1\n427| >>> next(p)\n428| Traceback (most recent call last):\n429| ...\n430| StopIteration\n431| \n432| \"\"\"\n433| self._cache.extendleft(reversed(items))\n434| \n435| def __next__(self):\n436| if self._cache:\n437| return self._cache.popleft()\n438| \n439| return next(self._it)\n440| \n441| def _get_slice(self, index):\n442| # Normalize the slice's arguments\n443| step = 1 if (index.step is None) else index.step\n444| if step > 0:\n445| start = 0 if (index.start is None) else index.start\n446| stop = maxsize if (index.stop is None) else index.stop\n447| elif step < 0:\n448| start = -1 if (index.start is None) else index.start\n449| stop = (-maxsize - 1) if (index.stop is None) else index.stop\n450| else:\n451| raise ValueError('slice step cannot be zero')\n452| \n453| # If either the start or stop index is negative, we'll need to cache\n454| # the rest of the iterable in order to slice from the right side.\n455| if (start < 0) or (stop < 0):\n456| self._cache.extend(self._it)\n457| # Otherwise we'll need to find the rightmost index and cache to that\n458| # point.\n459| else:\n460| n = min(max(start, stop) + 1, maxsize)\n461| cache_len = len(self._cache)\n462| if n >= cache_len:\n463| self._cache.extend(islice(self._it, n - cache_len))\n464| \n465| return list(self._cache)[index]\n466| \n467| def __getitem__(self, index):\n468| if isinstance(index, slice):\n469| return self._get_slice(index)\n470| \n471| cache_len = len(self._cache)\n472| if index < 0:\n473| self._cache.extend(self._it)\n474| elif index >= cache_len:\n475| self._cache.extend(islice(self._it, index + 1 - cache_len))\n476| \n477| return self._cache[index]\n478| \n479| \n480| def consumer(func):\n481| \"\"\"Decorator that automatically advances a PEP-342-style \"reverse iterator\"\n482| to its first yield point so you don't have to call ``next()`` on it\n483| manually.\n484| \n485| >>> @consumer",
|
|
14
|
+
"must_find": [
|
|
15
|
+
{
|
|
16
|
+
"regex": "^\\W*fault:\\s*line\\s*(?:286)\\b",
|
|
17
|
+
"label": "fault: line 286"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"must_not_claim": [
|
|
21
|
+
"no fault"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"shape": "rebench",
|
|
3
|
-
"source": "more-itertools__more-itertools-1028",
|
|
4
|
-
"upstream": "more-itertools/more-itertools",
|
|
5
|
-
"source_url": "https://github.com/more-itertools/more-itertools/pull/1028",
|
|
6
|
-
"created": "2025-07-14 00:35:41",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"score_in": "first_line",
|
|
9
|
-
"min_answer_chars": 8,
|
|
10
|
-
"id": "rebench-more-itertools-1028-control",
|
|
11
|
-
"title": "Real-bug control: say NO FAULT",
|
|
12
|
-
"why": "more_itertools/more.py after the fix in https://github.com/more-itertools/more-itertools/pull/1028; the paired bug task is the file before it. The answer is NO FAULT.",
|
|
13
|
-
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file (an excerpt: lines 86-485).\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 86| 'distinct_combinations',\n 87| 'distinct_permutations',\n 88| 'distribute',\n 89| 'divide',\n 90| 'doublestarmap',\n 91| 'duplicates_everseen',\n 92| 'duplicates_justseen',\n 93| 'classify_unique',\n 94| 'exactly_n',\n 95| 'filter_except',\n 96| 'filter_map',\n 97| 'first',\n 98| 'gray_product',\n 99| 'groupby_transform',\n100| 'ichunked',\n101| 'iequals',\n102| 'idft',\n103| 'ilen',\n104| 'interleave',\n105| 'interleave_evenly',\n106| 'interleave_longest',\n107| 'intersperse',\n108| 'is_sorted',\n109| 'islice_extended',\n110| 'iterate',\n111| 'iter_suppress',\n112| 'join_mappings',\n113| 'last',\n114| 'locate',\n115| 'longest_common_prefix',\n116| 'lstrip',\n117| 'make_decorator',\n118| 'map_except',\n119| 'map_if',\n120| 'map_reduce',\n121| 'mark_ends',\n122| 'minmax',\n123| 'nth_or_last',\n124| 'nth_permutation',\n125| 'nth_prime',\n126| 'nth_product',\n127| 'nth_combination_with_replacement',\n128| 'numeric_range',\n129| 'one',\n130| 'only',\n131| 'outer_product',\n132| 'padded',\n133| 'partial_product',\n134| 'partitions',\n135| 'peekable',\n136| 'permutation_index',\n137| 'powerset_of_sets',\n138| 'product_index',\n139| 'raise_',\n140| 'repeat_each',\n141| 'repeat_last',\n142| 'replace',\n143| 'rlocate',\n144| 'rstrip',\n145| 'run_length',\n146| 'sample',\n147| 'seekable',\n148| 'set_partitions',\n149| 'side_effect',\n150| 'sliced',\n151| 'sort_together',\n152| 'split_after',\n153| 'split_at',\n154| 'split_before',\n155| 'split_into',\n156| 'split_when',\n157| 'spy',\n158| 'stagger',\n159| 'strip',\n160| 'strictly_n',\n161| 'substrings',\n162| 'substrings_indexes',\n163| 'takewhile_inclusive',\n164| 'time_limited',\n165| 'unique_in_window',\n166| 'unique_to_each',\n167| 'unzip',\n168| 'value_chain',\n169| 'windowed',\n170| 'windowed_complete',\n171| 'with_iter',\n172| 'zip_broadcast',\n173| 'zip_equal',\n174| 'zip_offset',\n175| ]\n176| \n177| # math.sumprod is available for Python 3.12+\n178| try:\n179| from math import sumprod as _fsumprod\n180| \n181| except ImportError: # pragma: no cover\n182| # Extended precision algorithms from T. J. Dekker,\n183| # \"A Floating-Point Technique for Extending the Available Precision\"\n184| # https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf\n185| # Formulas: (5.5) (5.6) and (5.8). Code: mul12()\n186| \n187| def dl_split(x: float):\n188| \"Split a float into two half-precision components.\"\n189| t = x * 134217729.0 # Veltkamp constant = 2.0 ** 27 + 1\n190| hi = t - (t - x)\n191| lo = x - hi\n192| return hi, lo\n193| \n194| def dl_mul(x, y):\n195| \"Lossless multiplication.\"\n196| xx_hi, xx_lo = dl_split(x)\n197| yy_hi, yy_lo = dl_split(y)\n198| p = xx_hi * yy_hi\n199| q = xx_hi * yy_lo + xx_lo * yy_hi\n200| z = p + q\n201| zz = p - z + q + xx_lo * yy_lo\n202| return z, zz\n203| \n204| def _fsumprod(p, q):\n205| return fsum(chain.from_iterable(map(dl_mul, p, q)))\n206| \n207| \n208| def chunked(iterable, n, strict=False):\n209| \"\"\"Break *iterable* into lists of length *n*:\n210| \n211| >>> list(chunked([1, 2, 3, 4, 5, 6], 3))\n212| [[1, 2, 3], [4, 5, 6]]\n213| \n214| By the default, the last yielded list will have fewer than *n* elements\n215| if the length of *iterable* is not divisible by *n*:\n216| \n217| >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3))\n218| [[1, 2, 3], [4, 5, 6], [7, 8]]\n219| \n220| To use a fill-in value instead, see the :func:`grouper` recipe.\n221| \n222| If the length of *iterable* is not divisible by *n* and *strict* is\n223| ``True``, then ``ValueError`` will be raised before the last\n224| list is yielded.\n225| \n226| \"\"\"\n227| iterator = iter(partial(take, n, iter(iterable)), [])\n228| if strict:\n229| if n is None:\n230| raise ValueError('n must not be None when using strict mode.')\n231| \n232| def ret():\n233| for chunk in iterator:\n234| if len(chunk) != n:\n235| raise ValueError('iterable is not divisible by n.')\n236| yield chunk\n237| \n238| return ret()\n239| else:\n240| return iterator\n241| \n242| \n243| def first(iterable, default=_marker):\n244| \"\"\"Return the first item of *iterable*, or *default* if *iterable* is\n245| empty.\n246| \n247| >>> first([0, 1, 2, 3])\n248| 0\n249| >>> first([], 'some default')\n250| 'some default'\n251| \n252| If *default* is not provided and there are no items in the iterable,\n253| raise ``ValueError``.\n254| \n255| :func:`first` is useful when you have a generator of expensive-to-retrieve\n256| values and want any arbitrary one. It is marginally shorter than\n257| ``next(iter(iterable), default)``.\n258| \n259| \"\"\"\n260| for item in iterable:\n261| return item\n262| if default is _marker:\n263| raise ValueError(\n264| 'first() was called on an empty iterable, '\n265| 'and no default value was provided.'\n266| )\n267| return default\n268| \n269| \n270| def last(iterable, default=_marker):\n271| \"\"\"Return the last item of *iterable*, or *default* if *iterable* is\n272| empty.\n273| \n274| >>> last([0, 1, 2, 3])\n275| 3\n276| >>> last([], 'some default')\n277| 'some default'\n278| \n279| If *default* is not provided and there are no items in the iterable,\n280| raise ``ValueError``.\n281| \"\"\"\n282| try:\n283| if isinstance(iterable, Sequence):\n284| return iterable[-1]\n285| # Work around https://bugs.python.org/issue38525\n286| if getattr(iterable, '__reversed__', None):\n287| return next(reversed(iterable))\n288| return deque(iterable, maxlen=1)[-1]\n289| except (IndexError, TypeError, StopIteration):\n290| if default is _marker:\n291| raise ValueError(\n292| 'last() was called on an empty iterable, '\n293| 'and no default value was provided.'\n294| )\n295| return default\n296| \n297| \n298| def nth_or_last(iterable, n, default=_marker):\n299| \"\"\"Return the nth or the last item of *iterable*,\n300| or *default* if *iterable* is empty.\n301| \n302| >>> nth_or_last([0, 1, 2, 3], 2)\n303| 2\n304| >>> nth_or_last([0, 1], 2)\n305| 1\n306| >>> nth_or_last([], 0, 'some default')\n307| 'some default'\n308| \n309| If *default* is not provided and there are no items in the iterable,\n310| raise ``ValueError``.\n311| \"\"\"\n312| return last(islice(iterable, n + 1), default=default)\n313| \n314| \n315| class peekable:\n316| \"\"\"Wrap an iterator to allow lookahead and prepending elements.\n317| \n318| Call :meth:`peek` on the result to get the value that will be returned\n319| by :func:`next`. This won't advance the iterator:\n320| \n321| >>> p = peekable(['a', 'b'])\n322| >>> p.peek()\n323| 'a'\n324| >>> next(p)\n325| 'a'\n326| \n327| Pass :meth:`peek` a default value to return that instead of raising\n328| ``StopIteration`` when the iterator is exhausted.\n329| \n330| >>> p = peekable([])\n331| >>> p.peek('hi')\n332| 'hi'\n333| \n334| peekables also offer a :meth:`prepend` method, which \"inserts\" items\n335| at the head of the iterable:\n336| \n337| >>> p = peekable([1, 2, 3])\n338| >>> p.prepend(10, 11, 12)\n339| >>> next(p)\n340| 10\n341| >>> p.peek()\n342| 11\n343| >>> list(p)\n344| [11, 12, 1, 2, 3]\n345| \n346| peekables can be indexed. Index 0 is the item that will be returned by\n347| :func:`next`, index 1 is the item after that, and so on:\n348| The values up to the given index will be cached.\n349| \n350| >>> p = peekable(['a', 'b', 'c', 'd'])\n351| >>> p[0]\n352| 'a'\n353| >>> p[1]\n354| 'b'\n355| >>> next(p)\n356| 'a'\n357| \n358| Negative indexes are supported, but be aware that they will cache the\n359| remaining items in the source iterator, which may require significant\n360| storage.\n361| \n362| To check whether a peekable is exhausted, check its truth value:\n363| \n364| >>> p = peekable(['a', 'b'])\n365| >>> if p: # peekable has items\n366| ... list(p)\n367| ['a', 'b']\n368| >>> if not p: # peekable is exhausted\n369| ... list(p)\n370| []\n371| \n372| \"\"\"\n373| \n374| def __init__(self, iterable):\n375| self._it = iter(iterable)\n376| self._cache = deque()\n377| \n378| def __iter__(self):\n379| return self\n380| \n381| def __bool__(self):\n382| try:\n383| self.peek()\n384| except StopIteration:\n385| return False\n386| return True\n387| \n388| def peek(self, default=_marker):\n389| \"\"\"Return the item that will be next returned from ``next()``.\n390| \n391| Return ``default`` if there are no items left. If ``default`` is not\n392| provided, raise ``StopIteration``.\n393| \n394| \"\"\"\n395| if not self._cache:\n396| try:\n397| self._cache.append(next(self._it))\n398| except StopIteration:\n399| if default is _marker:\n400| raise\n401| return default\n402| return self._cache[0]\n403| \n404| def prepend(self, *items):\n405| \"\"\"Stack up items to be the next ones returned from ``next()`` or\n406| ``self.peek()``. The items will be returned in\n407| first in, first out order::\n408| \n409| >>> p = peekable([1, 2, 3])\n410| >>> p.prepend(10, 11, 12)\n411| >>> next(p)\n412| 10\n413| >>> list(p)\n414| [11, 12, 1, 2, 3]\n415| \n416| It is possible, by prepending items, to \"resurrect\" a peekable that\n417| previously raised ``StopIteration``.\n418| \n419| >>> p = peekable([])\n420| >>> next(p)\n421| Traceback (most recent call last):\n422| ...\n423| StopIteration\n424| >>> p.prepend(1)\n425| >>> next(p)\n426| 1\n427| >>> next(p)\n428| Traceback (most recent call last):\n429| ...\n430| StopIteration\n431| \n432| \"\"\"\n433| self._cache.extendleft(reversed(items))\n434| \n435| def __next__(self):\n436| if self._cache:\n437| return self._cache.popleft()\n438| \n439| return next(self._it)\n440| \n441| def _get_slice(self, index):\n442| # Normalize the slice's arguments\n443| step = 1 if (index.step is None) else index.step\n444| if step > 0:\n445| start = 0 if (index.start is None) else index.start\n446| stop = maxsize if (index.stop is None) else index.stop\n447| elif step < 0:\n448| start = -1 if (index.start is None) else index.start\n449| stop = (-maxsize - 1) if (index.stop is None) else index.stop\n450| else:\n451| raise ValueError('slice step cannot be zero')\n452| \n453| # If either the start or stop index is negative, we'll need to cache\n454| # the rest of the iterable in order to slice from the right side.\n455| if (start < 0) or (stop < 0):\n456| self._cache.extend(self._it)\n457| # Otherwise we'll need to find the rightmost index and cache to that\n458| # point.\n459| else:\n460| n = min(max(start, stop) + 1, maxsize)\n461| cache_len = len(self._cache)\n462| if n >= cache_len:\n463| self._cache.extend(islice(self._it, n - cache_len))\n464| \n465| return list(self._cache)[index]\n466| \n467| def __getitem__(self, index):\n468| if isinstance(index, slice):\n469| return self._get_slice(index)\n470| \n471| cache_len = len(self._cache)\n472| if index < 0:\n473| self._cache.extend(self._it)\n474| elif index >= cache_len:\n475| self._cache.extend(islice(self._it, index + 1 - cache_len))\n476| \n477| return self._cache[index]\n478| \n479| \n480| def consumer(func):\n481| \"\"\"Decorator that automatically advances a PEP-342-style \"reverse iterator\"\n482| to its first yield point so you don't have to call ``next()`` on it\n483| manually.\n484| \n485| >>> @consumer",
|
|
14
|
-
"must_find": [
|
|
15
|
-
{
|
|
16
|
-
"any_of": [
|
|
17
|
-
"no fault"
|
|
18
|
-
]
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"must_not_claim": [
|
|
22
|
-
{
|
|
23
|
-
"regex": "^\\W*fault:\\s*line",
|
|
24
|
-
"label": "fault: line"
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"shape": "rebench",
|
|
3
|
+
"source": "more-itertools__more-itertools-1028",
|
|
4
|
+
"upstream": "more-itertools/more-itertools",
|
|
5
|
+
"source_url": "https://github.com/more-itertools/more-itertools/pull/1028",
|
|
6
|
+
"created": "2025-07-14 00:35:41",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"score_in": "first_line",
|
|
9
|
+
"min_answer_chars": 8,
|
|
10
|
+
"id": "rebench-more-itertools-1028-control",
|
|
11
|
+
"title": "Real-bug control: say NO FAULT",
|
|
12
|
+
"why": "more_itertools/more.py after the fix in https://github.com/more-itertools/more-itertools/pull/1028; the paired bug task is the file before it. The answer is NO FAULT.",
|
|
13
|
+
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file (an excerpt: lines 86-485).\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n 86| 'distinct_combinations',\n 87| 'distinct_permutations',\n 88| 'distribute',\n 89| 'divide',\n 90| 'doublestarmap',\n 91| 'duplicates_everseen',\n 92| 'duplicates_justseen',\n 93| 'classify_unique',\n 94| 'exactly_n',\n 95| 'filter_except',\n 96| 'filter_map',\n 97| 'first',\n 98| 'gray_product',\n 99| 'groupby_transform',\n100| 'ichunked',\n101| 'iequals',\n102| 'idft',\n103| 'ilen',\n104| 'interleave',\n105| 'interleave_evenly',\n106| 'interleave_longest',\n107| 'intersperse',\n108| 'is_sorted',\n109| 'islice_extended',\n110| 'iterate',\n111| 'iter_suppress',\n112| 'join_mappings',\n113| 'last',\n114| 'locate',\n115| 'longest_common_prefix',\n116| 'lstrip',\n117| 'make_decorator',\n118| 'map_except',\n119| 'map_if',\n120| 'map_reduce',\n121| 'mark_ends',\n122| 'minmax',\n123| 'nth_or_last',\n124| 'nth_permutation',\n125| 'nth_prime',\n126| 'nth_product',\n127| 'nth_combination_with_replacement',\n128| 'numeric_range',\n129| 'one',\n130| 'only',\n131| 'outer_product',\n132| 'padded',\n133| 'partial_product',\n134| 'partitions',\n135| 'peekable',\n136| 'permutation_index',\n137| 'powerset_of_sets',\n138| 'product_index',\n139| 'raise_',\n140| 'repeat_each',\n141| 'repeat_last',\n142| 'replace',\n143| 'rlocate',\n144| 'rstrip',\n145| 'run_length',\n146| 'sample',\n147| 'seekable',\n148| 'set_partitions',\n149| 'side_effect',\n150| 'sliced',\n151| 'sort_together',\n152| 'split_after',\n153| 'split_at',\n154| 'split_before',\n155| 'split_into',\n156| 'split_when',\n157| 'spy',\n158| 'stagger',\n159| 'strip',\n160| 'strictly_n',\n161| 'substrings',\n162| 'substrings_indexes',\n163| 'takewhile_inclusive',\n164| 'time_limited',\n165| 'unique_in_window',\n166| 'unique_to_each',\n167| 'unzip',\n168| 'value_chain',\n169| 'windowed',\n170| 'windowed_complete',\n171| 'with_iter',\n172| 'zip_broadcast',\n173| 'zip_equal',\n174| 'zip_offset',\n175| ]\n176| \n177| # math.sumprod is available for Python 3.12+\n178| try:\n179| from math import sumprod as _fsumprod\n180| \n181| except ImportError: # pragma: no cover\n182| # Extended precision algorithms from T. J. Dekker,\n183| # \"A Floating-Point Technique for Extending the Available Precision\"\n184| # https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf\n185| # Formulas: (5.5) (5.6) and (5.8). Code: mul12()\n186| \n187| def dl_split(x: float):\n188| \"Split a float into two half-precision components.\"\n189| t = x * 134217729.0 # Veltkamp constant = 2.0 ** 27 + 1\n190| hi = t - (t - x)\n191| lo = x - hi\n192| return hi, lo\n193| \n194| def dl_mul(x, y):\n195| \"Lossless multiplication.\"\n196| xx_hi, xx_lo = dl_split(x)\n197| yy_hi, yy_lo = dl_split(y)\n198| p = xx_hi * yy_hi\n199| q = xx_hi * yy_lo + xx_lo * yy_hi\n200| z = p + q\n201| zz = p - z + q + xx_lo * yy_lo\n202| return z, zz\n203| \n204| def _fsumprod(p, q):\n205| return fsum(chain.from_iterable(map(dl_mul, p, q)))\n206| \n207| \n208| def chunked(iterable, n, strict=False):\n209| \"\"\"Break *iterable* into lists of length *n*:\n210| \n211| >>> list(chunked([1, 2, 3, 4, 5, 6], 3))\n212| [[1, 2, 3], [4, 5, 6]]\n213| \n214| By the default, the last yielded list will have fewer than *n* elements\n215| if the length of *iterable* is not divisible by *n*:\n216| \n217| >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3))\n218| [[1, 2, 3], [4, 5, 6], [7, 8]]\n219| \n220| To use a fill-in value instead, see the :func:`grouper` recipe.\n221| \n222| If the length of *iterable* is not divisible by *n* and *strict* is\n223| ``True``, then ``ValueError`` will be raised before the last\n224| list is yielded.\n225| \n226| \"\"\"\n227| iterator = iter(partial(take, n, iter(iterable)), [])\n228| if strict:\n229| if n is None:\n230| raise ValueError('n must not be None when using strict mode.')\n231| \n232| def ret():\n233| for chunk in iterator:\n234| if len(chunk) != n:\n235| raise ValueError('iterable is not divisible by n.')\n236| yield chunk\n237| \n238| return ret()\n239| else:\n240| return iterator\n241| \n242| \n243| def first(iterable, default=_marker):\n244| \"\"\"Return the first item of *iterable*, or *default* if *iterable* is\n245| empty.\n246| \n247| >>> first([0, 1, 2, 3])\n248| 0\n249| >>> first([], 'some default')\n250| 'some default'\n251| \n252| If *default* is not provided and there are no items in the iterable,\n253| raise ``ValueError``.\n254| \n255| :func:`first` is useful when you have a generator of expensive-to-retrieve\n256| values and want any arbitrary one. It is marginally shorter than\n257| ``next(iter(iterable), default)``.\n258| \n259| \"\"\"\n260| for item in iterable:\n261| return item\n262| if default is _marker:\n263| raise ValueError(\n264| 'first() was called on an empty iterable, '\n265| 'and no default value was provided.'\n266| )\n267| return default\n268| \n269| \n270| def last(iterable, default=_marker):\n271| \"\"\"Return the last item of *iterable*, or *default* if *iterable* is\n272| empty.\n273| \n274| >>> last([0, 1, 2, 3])\n275| 3\n276| >>> last([], 'some default')\n277| 'some default'\n278| \n279| If *default* is not provided and there are no items in the iterable,\n280| raise ``ValueError``.\n281| \"\"\"\n282| try:\n283| if isinstance(iterable, Sequence):\n284| return iterable[-1]\n285| # Work around https://bugs.python.org/issue38525\n286| if getattr(iterable, '__reversed__', None):\n287| return next(reversed(iterable))\n288| return deque(iterable, maxlen=1)[-1]\n289| except (IndexError, TypeError, StopIteration):\n290| if default is _marker:\n291| raise ValueError(\n292| 'last() was called on an empty iterable, '\n293| 'and no default value was provided.'\n294| )\n295| return default\n296| \n297| \n298| def nth_or_last(iterable, n, default=_marker):\n299| \"\"\"Return the nth or the last item of *iterable*,\n300| or *default* if *iterable* is empty.\n301| \n302| >>> nth_or_last([0, 1, 2, 3], 2)\n303| 2\n304| >>> nth_or_last([0, 1], 2)\n305| 1\n306| >>> nth_or_last([], 0, 'some default')\n307| 'some default'\n308| \n309| If *default* is not provided and there are no items in the iterable,\n310| raise ``ValueError``.\n311| \"\"\"\n312| return last(islice(iterable, n + 1), default=default)\n313| \n314| \n315| class peekable:\n316| \"\"\"Wrap an iterator to allow lookahead and prepending elements.\n317| \n318| Call :meth:`peek` on the result to get the value that will be returned\n319| by :func:`next`. This won't advance the iterator:\n320| \n321| >>> p = peekable(['a', 'b'])\n322| >>> p.peek()\n323| 'a'\n324| >>> next(p)\n325| 'a'\n326| \n327| Pass :meth:`peek` a default value to return that instead of raising\n328| ``StopIteration`` when the iterator is exhausted.\n329| \n330| >>> p = peekable([])\n331| >>> p.peek('hi')\n332| 'hi'\n333| \n334| peekables also offer a :meth:`prepend` method, which \"inserts\" items\n335| at the head of the iterable:\n336| \n337| >>> p = peekable([1, 2, 3])\n338| >>> p.prepend(10, 11, 12)\n339| >>> next(p)\n340| 10\n341| >>> p.peek()\n342| 11\n343| >>> list(p)\n344| [11, 12, 1, 2, 3]\n345| \n346| peekables can be indexed. Index 0 is the item that will be returned by\n347| :func:`next`, index 1 is the item after that, and so on:\n348| The values up to the given index will be cached.\n349| \n350| >>> p = peekable(['a', 'b', 'c', 'd'])\n351| >>> p[0]\n352| 'a'\n353| >>> p[1]\n354| 'b'\n355| >>> next(p)\n356| 'a'\n357| \n358| Negative indexes are supported, but be aware that they will cache the\n359| remaining items in the source iterator, which may require significant\n360| storage.\n361| \n362| To check whether a peekable is exhausted, check its truth value:\n363| \n364| >>> p = peekable(['a', 'b'])\n365| >>> if p: # peekable has items\n366| ... list(p)\n367| ['a', 'b']\n368| >>> if not p: # peekable is exhausted\n369| ... list(p)\n370| []\n371| \n372| \"\"\"\n373| \n374| def __init__(self, iterable):\n375| self._it = iter(iterable)\n376| self._cache = deque()\n377| \n378| def __iter__(self):\n379| return self\n380| \n381| def __bool__(self):\n382| try:\n383| self.peek()\n384| except StopIteration:\n385| return False\n386| return True\n387| \n388| def peek(self, default=_marker):\n389| \"\"\"Return the item that will be next returned from ``next()``.\n390| \n391| Return ``default`` if there are no items left. If ``default`` is not\n392| provided, raise ``StopIteration``.\n393| \n394| \"\"\"\n395| if not self._cache:\n396| try:\n397| self._cache.append(next(self._it))\n398| except StopIteration:\n399| if default is _marker:\n400| raise\n401| return default\n402| return self._cache[0]\n403| \n404| def prepend(self, *items):\n405| \"\"\"Stack up items to be the next ones returned from ``next()`` or\n406| ``self.peek()``. The items will be returned in\n407| first in, first out order::\n408| \n409| >>> p = peekable([1, 2, 3])\n410| >>> p.prepend(10, 11, 12)\n411| >>> next(p)\n412| 10\n413| >>> list(p)\n414| [11, 12, 1, 2, 3]\n415| \n416| It is possible, by prepending items, to \"resurrect\" a peekable that\n417| previously raised ``StopIteration``.\n418| \n419| >>> p = peekable([])\n420| >>> next(p)\n421| Traceback (most recent call last):\n422| ...\n423| StopIteration\n424| >>> p.prepend(1)\n425| >>> next(p)\n426| 1\n427| >>> next(p)\n428| Traceback (most recent call last):\n429| ...\n430| StopIteration\n431| \n432| \"\"\"\n433| self._cache.extendleft(reversed(items))\n434| \n435| def __next__(self):\n436| if self._cache:\n437| return self._cache.popleft()\n438| \n439| return next(self._it)\n440| \n441| def _get_slice(self, index):\n442| # Normalize the slice's arguments\n443| step = 1 if (index.step is None) else index.step\n444| if step > 0:\n445| start = 0 if (index.start is None) else index.start\n446| stop = maxsize if (index.stop is None) else index.stop\n447| elif step < 0:\n448| start = -1 if (index.start is None) else index.start\n449| stop = (-maxsize - 1) if (index.stop is None) else index.stop\n450| else:\n451| raise ValueError('slice step cannot be zero')\n452| \n453| # If either the start or stop index is negative, we'll need to cache\n454| # the rest of the iterable in order to slice from the right side.\n455| if (start < 0) or (stop < 0):\n456| self._cache.extend(self._it)\n457| # Otherwise we'll need to find the rightmost index and cache to that\n458| # point.\n459| else:\n460| n = min(max(start, stop) + 1, maxsize)\n461| cache_len = len(self._cache)\n462| if n >= cache_len:\n463| self._cache.extend(islice(self._it, n - cache_len))\n464| \n465| return list(self._cache)[index]\n466| \n467| def __getitem__(self, index):\n468| if isinstance(index, slice):\n469| return self._get_slice(index)\n470| \n471| cache_len = len(self._cache)\n472| if index < 0:\n473| self._cache.extend(self._it)\n474| elif index >= cache_len:\n475| self._cache.extend(islice(self._it, index + 1 - cache_len))\n476| \n477| return self._cache[index]\n478| \n479| \n480| def consumer(func):\n481| \"\"\"Decorator that automatically advances a PEP-342-style \"reverse iterator\"\n482| to its first yield point so you don't have to call ``next()`` on it\n483| manually.\n484| \n485| >>> @consumer",
|
|
14
|
+
"must_find": [
|
|
15
|
+
{
|
|
16
|
+
"any_of": [
|
|
17
|
+
"no fault"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"must_not_claim": [
|
|
22
|
+
{
|
|
23
|
+
"regex": "^\\W*fault:\\s*line",
|
|
24
|
+
"label": "fault: line"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"shape": "rebench",
|
|
3
|
-
"source": "narwhals-dev__narwhals-2864",
|
|
4
|
-
"upstream": "narwhals-dev/narwhals",
|
|
5
|
-
"source_url": "https://github.com/narwhals-dev/narwhals/pull/2864",
|
|
6
|
-
"created": "2025-07-21 08:49:06",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"score_in": "first_line",
|
|
9
|
-
"min_answer_chars": 8,
|
|
10
|
-
"id": "rebench-narwhals-2864-bug",
|
|
11
|
-
"title": "Real bug: name the line a later fix changed",
|
|
12
|
-
"why": "narwhals-dev/narwhals PR #2864, created 2025-07-21 08:49:06: https://github.com/narwhals-dev/narwhals/pull/2864\nThe fix in narwhals/_arrow/series.py (base 28acbd0e9a) changed line(s) 470, 471, 472:\n - return self._with_native(\n - pc_replace_with_mask(self.native, mask, values_native.take(indices_native))\n - )\n + return self._with_native(pc_replace_with_mask(self.native, mask, values_native))\nProblem: bug: `ArrowSeries.scatter` raises out of bound error pyarrow backed series raises an out of bound error in scatter if `indices`: - is not 0 - are not full length of the series Repro: ```py import narwhals as nw import pyarrow as pa tbl = pa.table({\"a\": [1, 2, 3], \"b\": [142, 124, 132]}) frame = nw.fr\nCheck the fix is the bug, and visible from this file alone, before removing draft.",
|
|
13
|
-
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file (an excerpt: lines 271-670).\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n271| return self._with_native(pc.power(other, ser))\n272| \n273| def __floordiv__(self, other: Any) -> Self:\n274| ser, other = extract_native(self, other)\n275| return self._with_native(floordiv_compat(ser, other))\n276| \n277| def __rfloordiv__(self, other: Any) -> Self:\n278| ser, other = extract_native(self, other)\n279| return self._with_native(floordiv_compat(other, ser))\n280| \n281| def __truediv__(self, other: Any) -> Self:\n282| ser, other = extract_native(self, other)\n283| return self._with_native(pc.divide(*cast_for_truediv(ser, other))) # type: ignore[type-var]\n284| \n285| def __rtruediv__(self, other: Any) -> Self:\n286| ser, other = extract_native(self, other)\n287| return self._with_native(pc.divide(*cast_for_truediv(other, ser))) # type: ignore[type-var]\n288| \n289| def __mod__(self, other: Any) -> Self:\n290| floor_div = (self // other).native\n291| ser, other = extract_native(self, other)\n292| res = pc.subtract(ser, pc.multiply(floor_div, other))\n293| return self._with_native(res)\n294| \n295| def __rmod__(self, other: Any) -> Self:\n296| floor_div = (other // self).native\n297| ser, other = extract_native(self, other)\n298| res = pc.subtract(other, pc.multiply(floor_div, ser))\n299| return self._with_native(res)\n300| \n301| def __invert__(self) -> Self:\n302| return self._with_native(pc.invert(self.native))\n303| \n304| @property\n305| def _type(self) -> pa.DataType:\n306| return self.native.type\n307| \n308| def len(self, *, _return_py_scalar: bool = True) -> int:\n309| return maybe_extract_py_scalar(len(self.native), _return_py_scalar)\n310| \n311| def filter(self, predicate: ArrowSeries | list[bool | None]) -> Self:\n312| other_native: Any\n313| if not is_list_of(predicate, bool):\n314| _, other_native = extract_native(self, predicate)\n315| else:\n316| other_native = predicate\n317| return self._with_native(self.native.filter(other_native))\n318| \n319| def mean(self, *, _return_py_scalar: bool = True) -> float:\n320| return maybe_extract_py_scalar(pc.mean(self.native), _return_py_scalar)\n321| \n322| def median(self, *, _return_py_scalar: bool = True) -> float:\n323| from narwhals.exceptions import InvalidOperationError\n324| \n325| if not self.dtype.is_numeric():\n326| msg = \"`median` operation not supported for non-numeric input type.\"\n327| raise InvalidOperationError(msg)\n328| \n329| return maybe_extract_py_scalar(\n330| pc.approximate_median(self.native), _return_py_scalar\n331| )\n332| \n333| def min(self, *, _return_py_scalar: bool = True) -> Any:\n334| return maybe_extract_py_scalar(pc.min(self.native), _return_py_scalar)\n335| \n336| def max(self, *, _return_py_scalar: bool = True) -> Any:\n337| return maybe_extract_py_scalar(pc.max(self.native), _return_py_scalar)\n338| \n339| def arg_min(self, *, _return_py_scalar: bool = True) -> int:\n340| index_min = pc.index(self.native, pc.min(self.native))\n341| return maybe_extract_py_scalar(index_min, _return_py_scalar)\n342| \n343| def arg_max(self, *, _return_py_scalar: bool = True) -> int:\n344| index_max = pc.index(self.native, pc.max(self.native))\n345| return maybe_extract_py_scalar(index_max, _return_py_scalar)\n346| \n347| def sum(self, *, _return_py_scalar: bool = True) -> float:\n348| return maybe_extract_py_scalar(\n349| pc.sum(self.native, min_count=0), _return_py_scalar\n350| )\n351| \n352| def drop_nulls(self) -> Self:\n353| return self._with_native(self.native.drop_null())\n354| \n355| def shift(self, n: int) -> Self:\n356| if n > 0:\n357| arrays = [nulls_like(n, self), *self.native[:-n].chunks]\n358| elif n < 0:\n359| arrays = [*self.native[-n:].chunks, nulls_like(-n, self)]\n360| else:\n361| return self._with_native(self.native)\n362| return self._with_native(pa.concat_arrays(arrays))\n363| \n364| def std(self, ddof: int, *, _return_py_scalar: bool = True) -> float:\n365| return maybe_extract_py_scalar(\n366| pc.stddev(self.native, ddof=ddof), _return_py_scalar\n367| )\n368| \n369| def var(self, ddof: int, *, _return_py_scalar: bool = True) -> float:\n370| return maybe_extract_py_scalar(\n371| pc.variance(self.native, ddof=ddof), _return_py_scalar\n372| )\n373| \n374| def skew(self, *, _return_py_scalar: bool = True) -> float | None:\n375| ser_not_null = self.native.drop_null()\n376| if len(ser_not_null) == 0:\n377| return None\n378| elif len(ser_not_null) == 1:\n379| return float(\"nan\")\n380| elif len(ser_not_null) == 2:\n381| return 0.0\n382| else:\n383| m = pc.subtract(ser_not_null, pc.mean(ser_not_null))\n384| m2 = pc.mean(pc.power(m, lit(2)))\n385| m3 = pc.mean(pc.power(m, lit(3)))\n386| biased_population_skewness = pc.divide(m3, pc.power(m2, lit(1.5)))\n387| return maybe_extract_py_scalar(biased_population_skewness, _return_py_scalar)\n388| \n389| def kurtosis(self, *, _return_py_scalar: bool = True) -> float | None:\n390| ser_not_null = self.native.drop_null()\n391| if len(ser_not_null) == 0:\n392| return None\n393| elif len(ser_not_null) == 1:\n394| return float(\"nan\")\n395| else:\n396| m = pc.subtract(ser_not_null, pc.mean(ser_not_null))\n397| m2 = pc.mean(pc.power(m, lit(2)))\n398| m4 = pc.mean(pc.power(m, lit(4)))\n399| k = pc.subtract(pc.divide(m4, pc.power(m2, lit(2))), lit(3))\n400| return maybe_extract_py_scalar(k, _return_py_scalar)\n401| \n402| def count(self, *, _return_py_scalar: bool = True) -> int:\n403| return maybe_extract_py_scalar(pc.count(self.native), _return_py_scalar)\n404| \n405| def n_unique(self, *, _return_py_scalar: bool = True) -> int:\n406| return maybe_extract_py_scalar(\n407| pc.count(self.native.unique(), mode=\"all\"), _return_py_scalar\n408| )\n409| \n410| def __native_namespace__(self) -> ModuleType:\n411| if self._implementation is Implementation.PYARROW:\n412| return self._implementation.to_native_namespace()\n413| \n414| msg = f\"Expected pyarrow, got: {type(self._implementation)}\" # pragma: no cover\n415| raise AssertionError(msg)\n416| \n417| @property\n418| def name(self) -> str:\n419| return self._name\n420| \n421| def _gather(self, rows: SizedMultiIndexSelector[ChunkedArrayAny]) -> Self:\n422| if len(rows) == 0:\n423| return self._with_native(self.native.slice(0, 0))\n424| if self._backend_version < (18,) and isinstance(rows, tuple):\n425| rows = list(rows)\n426| return self._with_native(self.native.take(rows))\n427| \n428| def _gather_slice(self, rows: _SliceIndex | range) -> Self:\n429| start = rows.start or 0\n430| stop = rows.stop if rows.stop is not None else len(self.native)\n431| if start < 0:\n432| start = len(self.native) + start\n433| if stop < 0:\n434| stop = len(self.native) + stop\n435| if rows.step is not None and rows.step != 1:\n436| msg = \"Slicing with step is not supported on PyArrow tables\"\n437| raise NotImplementedError(msg)\n438| return self._with_native(self.native.slice(start, stop - start))\n439| \n440| def scatter(self, indices: int | Sequence[int], values: Any) -> Self:\n441| import numpy as np # ignore-banned-import\n442| \n443| values_native: ArrayAny\n444| if isinstance(indices, int):\n445| indices_native = pa.array([indices])\n446| values_native = pa.array([values])\n447| else:\n448| # TODO(unassigned): we may also want to let `indices` be a Series.\n449| # https://github.com/narwhals-dev/narwhals/issues/2155\n450| indices_native = pa.array(indices)\n451| if isinstance(values, self.__class__):\n452| values_native = values.native.combine_chunks()\n453| else:\n454| # NOTE: Requires fixes in https://github.com/zen-xu/pyarrow-stubs/pull/209\n455| pa_array: Incomplete = pa.array\n456| values_native = pa_array(values)\n457| \n458| sorting_indices = pc.sort_indices(indices_native)\n459| indices_native = indices_native.take(sorting_indices)\n460| values_native = values_native.take(sorting_indices)\n461| \n462| mask: _1DArray = np.zeros(self.len(), dtype=bool)\n463| mask[indices_native] = True\n464| # NOTE: Multiple issues\n465| # - Missing `values` type\n466| # - `mask` accepts a `np.ndarray`, but not mentioned in stubs\n467| # - Missing `replacements` type\n468| # - Missing return type\n469| pc_replace_with_mask: Incomplete = pc.replace_with_mask\n470| return self._with_native(\n471| pc_replace_with_mask(self.native, mask, values_native.take(indices_native))\n472| )\n473| \n474| def to_list(self) -> list[Any]:\n475| return self.native.to_pylist()\n476| \n477| def __array__(self, dtype: Any = None, *, copy: bool | None = None) -> _1DArray:\n478| return self.native.__array__(dtype=dtype, copy=copy)\n479| \n480| def to_numpy(self, dtype: Any = None, *, copy: bool | None = None) -> _1DArray:\n481| return self.native.to_numpy()\n482| \n483| def alias(self, name: str) -> Self:\n484| result = self.__class__(self.native, name=name, version=self._version)\n485| result._broadcast = self._broadcast\n486| return result\n487| \n488| @property\n489| def dtype(self) -> DType:\n490| return native_to_narwhals_dtype(self.native.type, self._version)\n491| \n492| def abs(self) -> Self:\n493| return self._with_native(pc.abs(self.native))\n494| \n495| def cum_sum(self, *, reverse: bool) -> Self:\n496| cum_sum = pc.cumulative_sum\n497| result = (\n498| cum_sum(self.native, skip_nulls=True)\n499| if not reverse\n500| else cum_sum(self.native[::-1], skip_nulls=True)[::-1]\n501| )\n502| return self._with_native(result)\n503| \n504| def round(self, decimals: int) -> Self:\n505| return self._with_native(\n506| pc.round(self.native, decimals, round_mode=\"half_towards_infinity\")\n507| )\n508| \n509| def diff(self) -> Self:\n510| return self._with_native(pc.pairwise_diff(self.native.combine_chunks()))\n511| \n512| def any(self, *, _return_py_scalar: bool = True) -> bool:\n513| return maybe_extract_py_scalar(\n514| pc.any(self.native, min_count=0), _return_py_scalar\n515| )\n516| \n517| def all(self, *, _return_py_scalar: bool = True) -> bool:\n518| return maybe_extract_py_scalar(\n519| pc.all(self.native, min_count=0), _return_py_scalar\n520| )\n521| \n522| def is_between(\n523| self, lower_bound: Any, upper_bound: Any, closed: ClosedInterval\n524| ) -> Self:\n525| _, lower_bound = extract_native(self, lower_bound)\n526| _, upper_bound = extract_native(self, upper_bound)\n527| if closed == \"left\":\n528| ge = pc.greater_equal(self.native, lower_bound)\n529| lt = pc.less(self.native, upper_bound)\n530| res = pc.and_kleene(ge, lt)\n531| elif closed == \"right\":\n532| gt = pc.greater(self.native, lower_bound)\n533| le = pc.less_equal(self.native, upper_bound)\n534| res = pc.and_kleene(gt, le)\n535| elif closed == \"none\":\n536| gt = pc.greater(self.native, lower_bound)\n537| lt = pc.less(self.native, upper_bound)\n538| res = pc.and_kleene(gt, lt)\n539| elif closed == \"both\":\n540| ge = pc.greater_equal(self.native, lower_bound)\n541| le = pc.less_equal(self.native, upper_bound)\n542| res = pc.and_kleene(ge, le)\n543| else:\n544| assert_never(closed)\n545| return self._with_native(res)\n546| \n547| def is_null(self) -> Self:\n548| return self._with_native(self.native.is_null(), preserve_broadcast=True)\n549| \n550| def is_nan(self) -> Self:\n551| return self._with_native(pc.is_nan(self.native), preserve_broadcast=True)\n552| \n553| def cast(self, dtype: IntoDType) -> Self:\n554| data_type = narwhals_to_native_dtype(dtype, self._version)\n555| return self._with_native(pc.cast(self.native, data_type), preserve_broadcast=True)\n556| \n557| def null_count(self, *, _return_py_scalar: bool = True) -> int:\n558| return maybe_extract_py_scalar(self.native.null_count, _return_py_scalar)\n559| \n560| def head(self, n: int) -> Self:\n561| if n >= 0:\n562| return self._with_native(self.native.slice(0, n))\n563| else:\n564| num_rows = len(self)\n565| return self._with_native(self.native.slice(0, max(0, num_rows + n)))\n566| \n567| def tail(self, n: int) -> Self:\n568| if n >= 0:\n569| num_rows = len(self)\n570| return self._with_native(self.native.slice(max(0, num_rows - n)))\n571| else:\n572| return self._with_native(self.native.slice(abs(n)))\n573| \n574| def is_in(self, other: Any) -> Self:\n575| if self._is_native(other):\n576| value_set: ArrayOrChunkedArray = other\n577| else:\n578| value_set = pa.array(other)\n579| return self._with_native(pc.is_in(self.native, value_set=value_set))\n580| \n581| def arg_true(self) -> Self:\n582| import numpy as np # ignore-banned-import\n583| \n584| res = np.flatnonzero(self.native)\n585| return self.from_iterable(res, name=self.name, context=self)\n586| \n587| def item(self, index: int | None = None) -> Any:\n588| if index is None:\n589| if len(self) != 1:\n590| msg = (\n591| \"can only call '.item()' if the Series is of length 1,\"\n592| f\" or an explicit index is provided (Series is of length {len(self)})\"\n593| )\n594| raise ValueError(msg)\n595| return maybe_extract_py_scalar(self.native[0], return_py_scalar=True)\n596| return maybe_extract_py_scalar(self.native[index], return_py_scalar=True)\n597| \n598| def value_counts(\n599| self, *, sort: bool, parallel: bool, name: str | None, normalize: bool\n600| ) -> ArrowDataFrame:\n601| \"\"\"Parallel is unused, exists for compatibility.\"\"\"\n602| from narwhals._arrow.dataframe import ArrowDataFrame\n603| \n604| index_name_ = \"index\" if self._name is None else self._name\n605| value_name_ = name or (\"proportion\" if normalize else \"count\")\n606| \n607| val_counts = pc.value_counts(self.native)\n608| values = val_counts.field(\"values\")\n609| counts = cast(\"ChunkedArrayAny\", val_counts.field(\"counts\"))\n610| \n611| if normalize:\n612| arrays = [values, pc.divide(*cast_for_truediv(counts, pc.sum(counts)))]\n613| else:\n614| arrays = [values, counts]\n615| \n616| val_count = pa.Table.from_arrays(arrays, names=[index_name_, value_name_])\n617| \n618| if sort:\n619| val_count = val_count.sort_by([(value_name_, \"descending\")])\n620| \n621| return ArrowDataFrame(\n622| val_count, version=self._version, validate_column_names=True\n623| )\n624| \n625| def zip_with(self, mask: Self, other: Self) -> Self:\n626| cond = mask.native.combine_chunks()\n627| return self._with_native(pc.if_else(cond, self.native, other.native))\n628| \n629| def sample(\n630| self,\n631| n: int | None,\n632| *,\n633| fraction: float | None,\n634| with_replacement: bool,\n635| seed: int | None,\n636| ) -> Self:\n637| import numpy as np # ignore-banned-import\n638| \n639| num_rows = len(self)\n640| if n is None and fraction is not None:\n641| n = int(num_rows * fraction)\n642| \n643| rng = np.random.default_rng(seed=seed)\n644| idx = np.arange(num_rows)\n645| mask = rng.choice(idx, size=n, replace=with_replacement)\n646| return self._with_native(self.native.take(mask))\n647| \n648| def fill_null(\n649| self,\n650| value: Self | NonNestedLiteral,\n651| strategy: FillNullStrategy | None,\n652| limit: int | None,\n653| ) -> Self:\n654| import numpy as np # ignore-banned-import\n655| \n656| def fill_aux(\n657| arr: ChunkedArrayAny, limit: int, direction: FillNullStrategy | None\n658| ) -> ArrayAny:\n659| # this algorithm first finds the indices of the valid values to fill all the null value positions\n660| # then it calculates the distance of each new index and the original index\n661| # if the distance is equal to or less than the limit and the original value is null, it is replaced\n662| valid_mask = pc.is_valid(arr)\n663| indices = pa.array(np.arange(len(arr)), type=pa.int64())\n664| if direction == \"forward\":\n665| valid_index = np.maximum.accumulate(np.where(valid_mask, indices, -1))\n666| distance = indices - valid_index\n667| else:\n668| valid_index = np.minimum.accumulate(\n669| np.where(valid_mask[::-1], indices[::-1], len(arr))\n670| )[::-1]",
|
|
14
|
-
"must_find": [
|
|
15
|
-
{
|
|
16
|
-
"regex": "^\\W*fault:\\s*line\\s*(?:470|471|472)\\b",
|
|
17
|
-
"label": "fault: line 470 or 471 or 472"
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
"must_not_claim": [
|
|
21
|
-
"no fault"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"shape": "rebench",
|
|
3
|
+
"source": "narwhals-dev__narwhals-2864",
|
|
4
|
+
"upstream": "narwhals-dev/narwhals",
|
|
5
|
+
"source_url": "https://github.com/narwhals-dev/narwhals/pull/2864",
|
|
6
|
+
"created": "2025-07-21 08:49:06",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"score_in": "first_line",
|
|
9
|
+
"min_answer_chars": 8,
|
|
10
|
+
"id": "rebench-narwhals-2864-bug",
|
|
11
|
+
"title": "Real bug: name the line a later fix changed",
|
|
12
|
+
"why": "narwhals-dev/narwhals PR #2864, created 2025-07-21 08:49:06: https://github.com/narwhals-dev/narwhals/pull/2864\nThe fix in narwhals/_arrow/series.py (base 28acbd0e9a) changed line(s) 470, 471, 472:\n - return self._with_native(\n - pc_replace_with_mask(self.native, mask, values_native.take(indices_native))\n - )\n + return self._with_native(pc_replace_with_mask(self.native, mask, values_native))\nProblem: bug: `ArrowSeries.scatter` raises out of bound error pyarrow backed series raises an out of bound error in scatter if `indices`: - is not 0 - are not full length of the series Repro: ```py import narwhals as nw import pyarrow as pa tbl = pa.table({\"a\": [1, 2, 3], \"b\": [142, 124, 132]}) frame = nw.fr\nCheck the fix is the bug, and visible from this file alone, before removing draft.",
|
|
13
|
+
"prompt": "The Python file below is from a public project. Either it contains a bug that a later commit to the project fixed, or it is the version after that fix. Lines are numbered as in the file (an excerpt: lines 271-670).\n\nYour first line must be exactly `FAULT: line <n>`, naming a line of the bug (if the fix only added code, the line just before or after where it belongs), or `NO FAULT` if this is the fixed version. Then explain in at most three sentences. Plain ASCII.\n\n271| return self._with_native(pc.power(other, ser))\n272| \n273| def __floordiv__(self, other: Any) -> Self:\n274| ser, other = extract_native(self, other)\n275| return self._with_native(floordiv_compat(ser, other))\n276| \n277| def __rfloordiv__(self, other: Any) -> Self:\n278| ser, other = extract_native(self, other)\n279| return self._with_native(floordiv_compat(other, ser))\n280| \n281| def __truediv__(self, other: Any) -> Self:\n282| ser, other = extract_native(self, other)\n283| return self._with_native(pc.divide(*cast_for_truediv(ser, other))) # type: ignore[type-var]\n284| \n285| def __rtruediv__(self, other: Any) -> Self:\n286| ser, other = extract_native(self, other)\n287| return self._with_native(pc.divide(*cast_for_truediv(other, ser))) # type: ignore[type-var]\n288| \n289| def __mod__(self, other: Any) -> Self:\n290| floor_div = (self // other).native\n291| ser, other = extract_native(self, other)\n292| res = pc.subtract(ser, pc.multiply(floor_div, other))\n293| return self._with_native(res)\n294| \n295| def __rmod__(self, other: Any) -> Self:\n296| floor_div = (other // self).native\n297| ser, other = extract_native(self, other)\n298| res = pc.subtract(other, pc.multiply(floor_div, ser))\n299| return self._with_native(res)\n300| \n301| def __invert__(self) -> Self:\n302| return self._with_native(pc.invert(self.native))\n303| \n304| @property\n305| def _type(self) -> pa.DataType:\n306| return self.native.type\n307| \n308| def len(self, *, _return_py_scalar: bool = True) -> int:\n309| return maybe_extract_py_scalar(len(self.native), _return_py_scalar)\n310| \n311| def filter(self, predicate: ArrowSeries | list[bool | None]) -> Self:\n312| other_native: Any\n313| if not is_list_of(predicate, bool):\n314| _, other_native = extract_native(self, predicate)\n315| else:\n316| other_native = predicate\n317| return self._with_native(self.native.filter(other_native))\n318| \n319| def mean(self, *, _return_py_scalar: bool = True) -> float:\n320| return maybe_extract_py_scalar(pc.mean(self.native), _return_py_scalar)\n321| \n322| def median(self, *, _return_py_scalar: bool = True) -> float:\n323| from narwhals.exceptions import InvalidOperationError\n324| \n325| if not self.dtype.is_numeric():\n326| msg = \"`median` operation not supported for non-numeric input type.\"\n327| raise InvalidOperationError(msg)\n328| \n329| return maybe_extract_py_scalar(\n330| pc.approximate_median(self.native), _return_py_scalar\n331| )\n332| \n333| def min(self, *, _return_py_scalar: bool = True) -> Any:\n334| return maybe_extract_py_scalar(pc.min(self.native), _return_py_scalar)\n335| \n336| def max(self, *, _return_py_scalar: bool = True) -> Any:\n337| return maybe_extract_py_scalar(pc.max(self.native), _return_py_scalar)\n338| \n339| def arg_min(self, *, _return_py_scalar: bool = True) -> int:\n340| index_min = pc.index(self.native, pc.min(self.native))\n341| return maybe_extract_py_scalar(index_min, _return_py_scalar)\n342| \n343| def arg_max(self, *, _return_py_scalar: bool = True) -> int:\n344| index_max = pc.index(self.native, pc.max(self.native))\n345| return maybe_extract_py_scalar(index_max, _return_py_scalar)\n346| \n347| def sum(self, *, _return_py_scalar: bool = True) -> float:\n348| return maybe_extract_py_scalar(\n349| pc.sum(self.native, min_count=0), _return_py_scalar\n350| )\n351| \n352| def drop_nulls(self) -> Self:\n353| return self._with_native(self.native.drop_null())\n354| \n355| def shift(self, n: int) -> Self:\n356| if n > 0:\n357| arrays = [nulls_like(n, self), *self.native[:-n].chunks]\n358| elif n < 0:\n359| arrays = [*self.native[-n:].chunks, nulls_like(-n, self)]\n360| else:\n361| return self._with_native(self.native)\n362| return self._with_native(pa.concat_arrays(arrays))\n363| \n364| def std(self, ddof: int, *, _return_py_scalar: bool = True) -> float:\n365| return maybe_extract_py_scalar(\n366| pc.stddev(self.native, ddof=ddof), _return_py_scalar\n367| )\n368| \n369| def var(self, ddof: int, *, _return_py_scalar: bool = True) -> float:\n370| return maybe_extract_py_scalar(\n371| pc.variance(self.native, ddof=ddof), _return_py_scalar\n372| )\n373| \n374| def skew(self, *, _return_py_scalar: bool = True) -> float | None:\n375| ser_not_null = self.native.drop_null()\n376| if len(ser_not_null) == 0:\n377| return None\n378| elif len(ser_not_null) == 1:\n379| return float(\"nan\")\n380| elif len(ser_not_null) == 2:\n381| return 0.0\n382| else:\n383| m = pc.subtract(ser_not_null, pc.mean(ser_not_null))\n384| m2 = pc.mean(pc.power(m, lit(2)))\n385| m3 = pc.mean(pc.power(m, lit(3)))\n386| biased_population_skewness = pc.divide(m3, pc.power(m2, lit(1.5)))\n387| return maybe_extract_py_scalar(biased_population_skewness, _return_py_scalar)\n388| \n389| def kurtosis(self, *, _return_py_scalar: bool = True) -> float | None:\n390| ser_not_null = self.native.drop_null()\n391| if len(ser_not_null) == 0:\n392| return None\n393| elif len(ser_not_null) == 1:\n394| return float(\"nan\")\n395| else:\n396| m = pc.subtract(ser_not_null, pc.mean(ser_not_null))\n397| m2 = pc.mean(pc.power(m, lit(2)))\n398| m4 = pc.mean(pc.power(m, lit(4)))\n399| k = pc.subtract(pc.divide(m4, pc.power(m2, lit(2))), lit(3))\n400| return maybe_extract_py_scalar(k, _return_py_scalar)\n401| \n402| def count(self, *, _return_py_scalar: bool = True) -> int:\n403| return maybe_extract_py_scalar(pc.count(self.native), _return_py_scalar)\n404| \n405| def n_unique(self, *, _return_py_scalar: bool = True) -> int:\n406| return maybe_extract_py_scalar(\n407| pc.count(self.native.unique(), mode=\"all\"), _return_py_scalar\n408| )\n409| \n410| def __native_namespace__(self) -> ModuleType:\n411| if self._implementation is Implementation.PYARROW:\n412| return self._implementation.to_native_namespace()\n413| \n414| msg = f\"Expected pyarrow, got: {type(self._implementation)}\" # pragma: no cover\n415| raise AssertionError(msg)\n416| \n417| @property\n418| def name(self) -> str:\n419| return self._name\n420| \n421| def _gather(self, rows: SizedMultiIndexSelector[ChunkedArrayAny]) -> Self:\n422| if len(rows) == 0:\n423| return self._with_native(self.native.slice(0, 0))\n424| if self._backend_version < (18,) and isinstance(rows, tuple):\n425| rows = list(rows)\n426| return self._with_native(self.native.take(rows))\n427| \n428| def _gather_slice(self, rows: _SliceIndex | range) -> Self:\n429| start = rows.start or 0\n430| stop = rows.stop if rows.stop is not None else len(self.native)\n431| if start < 0:\n432| start = len(self.native) + start\n433| if stop < 0:\n434| stop = len(self.native) + stop\n435| if rows.step is not None and rows.step != 1:\n436| msg = \"Slicing with step is not supported on PyArrow tables\"\n437| raise NotImplementedError(msg)\n438| return self._with_native(self.native.slice(start, stop - start))\n439| \n440| def scatter(self, indices: int | Sequence[int], values: Any) -> Self:\n441| import numpy as np # ignore-banned-import\n442| \n443| values_native: ArrayAny\n444| if isinstance(indices, int):\n445| indices_native = pa.array([indices])\n446| values_native = pa.array([values])\n447| else:\n448| # TODO(unassigned): we may also want to let `indices` be a Series.\n449| # https://github.com/narwhals-dev/narwhals/issues/2155\n450| indices_native = pa.array(indices)\n451| if isinstance(values, self.__class__):\n452| values_native = values.native.combine_chunks()\n453| else:\n454| # NOTE: Requires fixes in https://github.com/zen-xu/pyarrow-stubs/pull/209\n455| pa_array: Incomplete = pa.array\n456| values_native = pa_array(values)\n457| \n458| sorting_indices = pc.sort_indices(indices_native)\n459| indices_native = indices_native.take(sorting_indices)\n460| values_native = values_native.take(sorting_indices)\n461| \n462| mask: _1DArray = np.zeros(self.len(), dtype=bool)\n463| mask[indices_native] = True\n464| # NOTE: Multiple issues\n465| # - Missing `values` type\n466| # - `mask` accepts a `np.ndarray`, but not mentioned in stubs\n467| # - Missing `replacements` type\n468| # - Missing return type\n469| pc_replace_with_mask: Incomplete = pc.replace_with_mask\n470| return self._with_native(\n471| pc_replace_with_mask(self.native, mask, values_native.take(indices_native))\n472| )\n473| \n474| def to_list(self) -> list[Any]:\n475| return self.native.to_pylist()\n476| \n477| def __array__(self, dtype: Any = None, *, copy: bool | None = None) -> _1DArray:\n478| return self.native.__array__(dtype=dtype, copy=copy)\n479| \n480| def to_numpy(self, dtype: Any = None, *, copy: bool | None = None) -> _1DArray:\n481| return self.native.to_numpy()\n482| \n483| def alias(self, name: str) -> Self:\n484| result = self.__class__(self.native, name=name, version=self._version)\n485| result._broadcast = self._broadcast\n486| return result\n487| \n488| @property\n489| def dtype(self) -> DType:\n490| return native_to_narwhals_dtype(self.native.type, self._version)\n491| \n492| def abs(self) -> Self:\n493| return self._with_native(pc.abs(self.native))\n494| \n495| def cum_sum(self, *, reverse: bool) -> Self:\n496| cum_sum = pc.cumulative_sum\n497| result = (\n498| cum_sum(self.native, skip_nulls=True)\n499| if not reverse\n500| else cum_sum(self.native[::-1], skip_nulls=True)[::-1]\n501| )\n502| return self._with_native(result)\n503| \n504| def round(self, decimals: int) -> Self:\n505| return self._with_native(\n506| pc.round(self.native, decimals, round_mode=\"half_towards_infinity\")\n507| )\n508| \n509| def diff(self) -> Self:\n510| return self._with_native(pc.pairwise_diff(self.native.combine_chunks()))\n511| \n512| def any(self, *, _return_py_scalar: bool = True) -> bool:\n513| return maybe_extract_py_scalar(\n514| pc.any(self.native, min_count=0), _return_py_scalar\n515| )\n516| \n517| def all(self, *, _return_py_scalar: bool = True) -> bool:\n518| return maybe_extract_py_scalar(\n519| pc.all(self.native, min_count=0), _return_py_scalar\n520| )\n521| \n522| def is_between(\n523| self, lower_bound: Any, upper_bound: Any, closed: ClosedInterval\n524| ) -> Self:\n525| _, lower_bound = extract_native(self, lower_bound)\n526| _, upper_bound = extract_native(self, upper_bound)\n527| if closed == \"left\":\n528| ge = pc.greater_equal(self.native, lower_bound)\n529| lt = pc.less(self.native, upper_bound)\n530| res = pc.and_kleene(ge, lt)\n531| elif closed == \"right\":\n532| gt = pc.greater(self.native, lower_bound)\n533| le = pc.less_equal(self.native, upper_bound)\n534| res = pc.and_kleene(gt, le)\n535| elif closed == \"none\":\n536| gt = pc.greater(self.native, lower_bound)\n537| lt = pc.less(self.native, upper_bound)\n538| res = pc.and_kleene(gt, lt)\n539| elif closed == \"both\":\n540| ge = pc.greater_equal(self.native, lower_bound)\n541| le = pc.less_equal(self.native, upper_bound)\n542| res = pc.and_kleene(ge, le)\n543| else:\n544| assert_never(closed)\n545| return self._with_native(res)\n546| \n547| def is_null(self) -> Self:\n548| return self._with_native(self.native.is_null(), preserve_broadcast=True)\n549| \n550| def is_nan(self) -> Self:\n551| return self._with_native(pc.is_nan(self.native), preserve_broadcast=True)\n552| \n553| def cast(self, dtype: IntoDType) -> Self:\n554| data_type = narwhals_to_native_dtype(dtype, self._version)\n555| return self._with_native(pc.cast(self.native, data_type), preserve_broadcast=True)\n556| \n557| def null_count(self, *, _return_py_scalar: bool = True) -> int:\n558| return maybe_extract_py_scalar(self.native.null_count, _return_py_scalar)\n559| \n560| def head(self, n: int) -> Self:\n561| if n >= 0:\n562| return self._with_native(self.native.slice(0, n))\n563| else:\n564| num_rows = len(self)\n565| return self._with_native(self.native.slice(0, max(0, num_rows + n)))\n566| \n567| def tail(self, n: int) -> Self:\n568| if n >= 0:\n569| num_rows = len(self)\n570| return self._with_native(self.native.slice(max(0, num_rows - n)))\n571| else:\n572| return self._with_native(self.native.slice(abs(n)))\n573| \n574| def is_in(self, other: Any) -> Self:\n575| if self._is_native(other):\n576| value_set: ArrayOrChunkedArray = other\n577| else:\n578| value_set = pa.array(other)\n579| return self._with_native(pc.is_in(self.native, value_set=value_set))\n580| \n581| def arg_true(self) -> Self:\n582| import numpy as np # ignore-banned-import\n583| \n584| res = np.flatnonzero(self.native)\n585| return self.from_iterable(res, name=self.name, context=self)\n586| \n587| def item(self, index: int | None = None) -> Any:\n588| if index is None:\n589| if len(self) != 1:\n590| msg = (\n591| \"can only call '.item()' if the Series is of length 1,\"\n592| f\" or an explicit index is provided (Series is of length {len(self)})\"\n593| )\n594| raise ValueError(msg)\n595| return maybe_extract_py_scalar(self.native[0], return_py_scalar=True)\n596| return maybe_extract_py_scalar(self.native[index], return_py_scalar=True)\n597| \n598| def value_counts(\n599| self, *, sort: bool, parallel: bool, name: str | None, normalize: bool\n600| ) -> ArrowDataFrame:\n601| \"\"\"Parallel is unused, exists for compatibility.\"\"\"\n602| from narwhals._arrow.dataframe import ArrowDataFrame\n603| \n604| index_name_ = \"index\" if self._name is None else self._name\n605| value_name_ = name or (\"proportion\" if normalize else \"count\")\n606| \n607| val_counts = pc.value_counts(self.native)\n608| values = val_counts.field(\"values\")\n609| counts = cast(\"ChunkedArrayAny\", val_counts.field(\"counts\"))\n610| \n611| if normalize:\n612| arrays = [values, pc.divide(*cast_for_truediv(counts, pc.sum(counts)))]\n613| else:\n614| arrays = [values, counts]\n615| \n616| val_count = pa.Table.from_arrays(arrays, names=[index_name_, value_name_])\n617| \n618| if sort:\n619| val_count = val_count.sort_by([(value_name_, \"descending\")])\n620| \n621| return ArrowDataFrame(\n622| val_count, version=self._version, validate_column_names=True\n623| )\n624| \n625| def zip_with(self, mask: Self, other: Self) -> Self:\n626| cond = mask.native.combine_chunks()\n627| return self._with_native(pc.if_else(cond, self.native, other.native))\n628| \n629| def sample(\n630| self,\n631| n: int | None,\n632| *,\n633| fraction: float | None,\n634| with_replacement: bool,\n635| seed: int | None,\n636| ) -> Self:\n637| import numpy as np # ignore-banned-import\n638| \n639| num_rows = len(self)\n640| if n is None and fraction is not None:\n641| n = int(num_rows * fraction)\n642| \n643| rng = np.random.default_rng(seed=seed)\n644| idx = np.arange(num_rows)\n645| mask = rng.choice(idx, size=n, replace=with_replacement)\n646| return self._with_native(self.native.take(mask))\n647| \n648| def fill_null(\n649| self,\n650| value: Self | NonNestedLiteral,\n651| strategy: FillNullStrategy | None,\n652| limit: int | None,\n653| ) -> Self:\n654| import numpy as np # ignore-banned-import\n655| \n656| def fill_aux(\n657| arr: ChunkedArrayAny, limit: int, direction: FillNullStrategy | None\n658| ) -> ArrayAny:\n659| # this algorithm first finds the indices of the valid values to fill all the null value positions\n660| # then it calculates the distance of each new index and the original index\n661| # if the distance is equal to or less than the limit and the original value is null, it is replaced\n662| valid_mask = pc.is_valid(arr)\n663| indices = pa.array(np.arange(len(arr)), type=pa.int64())\n664| if direction == \"forward\":\n665| valid_index = np.maximum.accumulate(np.where(valid_mask, indices, -1))\n666| distance = indices - valid_index\n667| else:\n668| valid_index = np.minimum.accumulate(\n669| np.where(valid_mask[::-1], indices[::-1], len(arr))\n670| )[::-1]",
|
|
14
|
+
"must_find": [
|
|
15
|
+
{
|
|
16
|
+
"regex": "^\\W*fault:\\s*line\\s*(?:470|471|472)\\b",
|
|
17
|
+
"label": "fault: line 470 or 471 or 472"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"must_not_claim": [
|
|
21
|
+
"no fault"
|
|
22
|
+
]
|
|
23
|
+
}
|