{ "tasks": [ { "id": "train_cache_mutation_shared_list", "split": "train", "title": "Cache mutation due to shared list reference", "instruction": "The cache stores references to lists, causing data to be unintentionally mutated when the original list changes. The cache should store a defensive copy of the list.", "files": { "cache.py": "class Cache:\n def __init__(self):\n self._cache = {}\n def set(self, key, value):\n self._cache[key] = value\n def get(self, key):\n return self._cache.get(key)", "tests/test_cache.py": "from cache import Cache\n\ndef test_cache_defensive_copy():\n c = Cache()\n data = [1, 2]\n c.set('a', data)\n data.append(3)\n cached = c.get('a')\n assert cached == [1, 2], f\"Expected [1, 2], got {cached}\"" }, "checks": [ { "type": "contains", "path": "cache.py", "text": "list(value)" }, { "type": "not_contains", "path": "cache.py", "text": "self._cache[key] = value" }, { "type": "regex", "path": "cache.py", "pattern": "self\\._cache\\[key\\] = .*copy" } ], "failure_messages": [ "Cache does not make a defensive copy of the list.", "Cache still stores a direct reference to the list.", "Cache assignment should use a copy of the value." ], "canonical_solution": "Wrap value with list() or use .copy() when storing in cache to avoid mutation." }, { "id": "train_py_timeout_zero_bug", "split": "train", "title": "Timeout helper treats zero as infinite", "instruction": "A timeout helper function treats timeout=0 as no timeout instead of immediate timeout. The function should treat zero as an immediate timeout.", "files": { "timeout_helper.py": "def has_timed_out(start, timeout, now):\n if timeout is None:\n return False\n if timeout <= 0:\n return False # BUG: should be True\n return (now - start) > timeout", "tests/test_timeout.py": "from timeout_helper import has_timed_out\n\ndef test_timeout_zero():\n assert has_timed_out(10, 0, 10) == True\n assert has_timed_out(10, None, 12) == False" }, "checks": [ { "type": "contains", "path": "timeout_helper.py", "text": "return True" }, { "type": "not_contains", "path": "timeout_helper.py", "text": "return False # BUG: should be True" }, { "type": "regex", "path": "timeout_helper.py", "pattern": "if timeout <= 0:.*return True" } ], "failure_messages": [ "Timeout of 0 does not cause immediate timeout.", "Zero timeout still returns False.", "Timeout helper does not return True for timeout <= 0." ], "canonical_solution": "Return True for timeout <= 0 to indicate an immediate timeout." }, { "id": "train_py_retry_backoff_not_applied", "split": "train", "title": "Retry helper ignores backoff delay", "instruction": "A retry helper is supposed to apply a backoff delay between attempts but currently does not. It should call the provided backoff function after each failed attempt except the last.", "files": { "retry.py": "def retry(retries, func, backoff):\n for i in range(retries):\n try:\n return func()\n except Exception:\n continue # Should apply backoff here\n raise RuntimeError('All retries failed')", "tests/test_retry.py": "from retry import retry\n\ndef test_retry_applies_backoff():\n calls = []\n def func():\n calls.append('try')\n raise ValueError()\n backoffs = []\n def backoff():\n backoffs.append('b')\n try:\n retry(3, func, backoff)\n except RuntimeError:\n pass\n assert backoffs == ['b', 'b'], f\"Expected 2 backoff calls, got {len(backoffs)}\"" }, "checks": [ { "type": "contains", "path": "retry.py", "text": "backoff()" }, { "type": "regex", "path": "retry.py", "pattern": "except Exception:\\s*backoff\\(\\)" }, { "type": "not_contains", "path": "retry.py", "text": "continue # Should apply backoff here" } ], "failure_messages": [ "Backoff is not called after failed retry attempts.", "Missing call to backoff() after exceptions.", "Backoff is not applied between retries." ], "canonical_solution": "Call backoff() in the except block before continuing to next retry." }, { "id": "train_py_registry_filter_incorrect", "split": "train", "title": "Registry filter fails to exclude items", "instruction": "A registry filtering method does not properly exclude items by type. The filter should only return registered items matching the given type.", "files": { "registry.py": "class Registry:\n def __init__(self):\n self.items = []\n def register(self, item):\n self.items.append(item)\n def filter_by_type(self, typ):\n return self.items # BUG: should filter by typ", "tests/test_registry.py": "from registry import Registry\n\ndef test_filter_by_type():\n class A: pass\n class B: pass\n r = Registry()\n a = A(); b = B()\n r.register(a)\n r.register(b)\n result = r.filter_by_type(A)\n assert result == [a], f\"Expected only A instance, got {result}\"" }, "checks": [ { "type": "contains", "path": "registry.py", "text": "isinstance(item, typ)" }, { "type": "not_contains", "path": "registry.py", "text": "return self.items # BUG: should filter by typ" }, { "type": "regex", "path": "registry.py", "pattern": "return \\[item for item in self\\.items if isinstance\\(item, typ\\)\\]" } ], "failure_messages": [ "filter_by_type does not filter by type.", "Returned all items instead of just matching type.", "Registry does not exclude items of the wrong type." ], "canonical_solution": "Return a filtered list with isinstance(item, typ) in filter_by_type." }, { "id": "train_test_discovery_missing_test", "split": "train", "title": "Test discovery skips non-prefixed test files", "instruction": "The test discovery script only finds files with a 'test_' prefix but should also include files with a '_test.py' suffix.", "files": { "discover.py": "import os\n\ndef discover_tests():\n return [f for f in os.listdir('tests') if f.startswith('test_') and f.endswith('.py')]", "tests/test_discovery.py": "# test_discovery.py\nfrom discover import discover_tests\n\ndef test_discovers_suffix_files(tmp_path, monkeypatch):\n d = tmp_path / 'tests'\n d.mkdir()\n (d / 'test_a.py').write_text('pass')\n (d / 'b_test.py').write_text('pass')\n monkeypatch.setattr('os.listdir', lambda _: ['test_a.py', 'b_test.py'])\n out = discover_tests()\n assert 'b_test.py' in out, f\"Discovery failed to find b_test.py: {out}\"" }, "checks": [ { "type": "contains", "path": "discover.py", "text": "or f.endswith('_test.py')" }, { "type": "regex", "path": "discover.py", "pattern": "f\\.startswith\\('test_'\\)|f\\.endswith\\('_test\\.py'\\)" } ], "failure_messages": [ "Discovery does not find files with '_test.py' suffix.", "Test files not starting with prefix are skipped." ], "canonical_solution": "Include both files with 'test_' prefix and '_test.py' suffix in discovery." }, { "id": "train_plugin_ordering_bug", "split": "train", "title": "Plugin ordering not preserved", "instruction": "The plugin registry should preserve the order in which plugins are registered, but it currently sorts them alphabetically. It should keep insertion order.", "files": { "plugin.py": "class PluginRegistry:\n def __init__(self):\n self.plugins = []\n def register(self, plugin):\n self.plugins.append(plugin)\n def get_plugins(self):\n return sorted(self.plugins, key=lambda x: x.__name__)", "tests/test_plugin.py": "from plugin import PluginRegistry\n\ndef test_plugin_ordering():\n class A: pass\n class B: pass\n reg = PluginRegistry()\n reg.register(A)\n reg.register(B)\n order = reg.get_plugins()\n assert order == [A, B], f\"Expected [A, B], got {order}\"" }, "checks": [ { "type": "not_contains", "path": "plugin.py", "text": "sorted(self.plugins" }, { "type": "contains", "path": "plugin.py", "text": "return self.plugins" } ], "failure_messages": [ "Plugins are not returned in registration order.", "get_plugins still sorts plugins alphabetically." ], "canonical_solution": "Remove the sorted call; just return self.plugins to preserve registration order." }, { "id": "eval_js_trim_slash_array_bug", "split": "eval", "title": "JS utility does not trim slashes from all array entries", "instruction": "A JavaScript utility is supposed to trim leading and trailing slashes from every string in an array, but it only works on the first element. All elements should be trimmed.", "files": { "utils/trimSlashes.js": "function trimSlashes(arr) {\n arr[0] = arr[0].replace(/^\\/+|\\/+$/g, '');\n return arr;\n}\nmodule.exports = trimSlashes;", "tests/test_trimSlashes.js": "const trimSlashes = require('../utils/trimSlashes');\n\ntest('trims slashes in all entries', () => {\n expect(trimSlashes(['/foo/', '/bar/', '/baz/'])).toEqual(['foo', 'bar', 'baz']);\n});" }, "checks": [ { "type": "contains", "path": "utils/trimSlashes.js", "text": "map(" }, { "type": "regex", "path": "utils/trimSlashes.js", "pattern": "\\.map\\(.*replace\\(" }, { "type": "not_contains", "path": "utils/trimSlashes.js", "text": "arr[0] =" } ], "failure_messages": [ "Only the first array element is trimmed.", "Should use map to trim all array entries.", "Direct assignment to arr[0] is still present." ], "canonical_solution": "Use arr.map to apply the replace to all entries in the array." }, { "id": "eval_js_package_script_order_bug", "split": "eval", "title": "JS package scripts run in incorrect order", "instruction": "The package scripts runner executes scripts in object key order, not in the order defined in the scripts array. It should maintain the declared order.", "files": { "scripts/runScripts.js": "function runScripts(scripts, actions) {\n const keys = Object.keys(scripts);\n keys.forEach(k => actions.push(k));\n}\nmodule.exports = runScripts;", "tests/test_runScripts.js": "const runScripts = require('../scripts/runScripts');\n\ntest('runs in order', () => {\n const scripts = {build: '', test: '', lint: ''};\n const order = [];\n runScripts(['lint', 'build', 'test'], order);\n expect(order).toEqual(['lint', 'build', 'test']);\n});" }, "checks": [ { "type": "not_contains", "path": "scripts/runScripts.js", "text": "Object.keys" }, { "type": "contains", "path": "scripts/runScripts.js", "text": "forEach(" } ], "failure_messages": [ "Uses object key order instead of provided array order.", "Should iterate over scripts array, not Object.keys." ], "canonical_solution": "Iterate over the provided scripts array and push keys in order." } ] }