|
| 1 | +# Quality registries. |
| 2 | +# |
| 3 | +# Source of truth for the rubric checks in `scripts/check_*.py`. |
| 4 | +# Each entry pins a contrast or footgun to a single owning page, so the |
| 5 | +# catalog has exactly one home for the lesson and verifiers can prove it. |
| 6 | + |
| 7 | +[[confusable_pairs]] |
| 8 | +name = "__str__ vs __repr__" |
| 9 | +owner = "special-methods" |
| 10 | +tokens = ["__str__", "__repr__"] |
| 11 | + |
| 12 | +[[confusable_pairs]] |
| 13 | +name = "is vs ==" |
| 14 | +owner = "equality-and-identity" |
| 15 | +tokens = [" is ", "=="] |
| 16 | + |
| 17 | +[[confusable_pairs]] |
| 18 | +name = "list vs tuple" |
| 19 | +owner = "tuples" |
| 20 | +tokens = ["list", "tuple"] |
| 21 | + |
| 22 | +[[confusable_pairs]] |
| 23 | +name = "classmethod vs staticmethod vs instance method" |
| 24 | +owner = "classmethods-and-staticmethods" |
| 25 | +tokens = ["@classmethod", "@staticmethod", "self"] |
| 26 | + |
| 27 | +[[confusable_pairs]] |
| 28 | +name = "isinstance vs type==" |
| 29 | +owner = "runtime-type-checks" |
| 30 | +tokens = ["isinstance(", "type("] |
| 31 | + |
| 32 | +[[confusable_pairs]] |
| 33 | +name = "generator vs class iterator" |
| 34 | +owner = "generators" |
| 35 | +tokens = ["yield", "__next__"] |
| 36 | + |
| 37 | +[[confusable_pairs]] |
| 38 | +name = "iterator vs iterable" |
| 39 | +owner = "iterator-vs-iterable" |
| 40 | +tokens = ["iterable", "iterator", "iter("] |
| 41 | + |
| 42 | +[[confusable_pairs]] |
| 43 | +name = "mutable vs immutable class attributes" |
| 44 | +owner = "classes" |
| 45 | +tokens = ["class attribute", "__init__"] |
| 46 | + |
| 47 | +[[confusable_pairs]] |
| 48 | +name = "eager vs lazy production" |
| 49 | +owner = "generators" |
| 50 | +tokens = ["return", "yield"] |
| 51 | + |
| 52 | +[[confusable_pairs]] |
| 53 | +name = "Protocol vs ABC" |
| 54 | +owner = "abstract-base-classes" |
| 55 | +tokens = ["Protocol", "ABC"] |
| 56 | + |
| 57 | +[[confusable_pairs]] |
| 58 | +name = "dataclass vs NamedTuple vs TypedDict" |
| 59 | +owner = "structured-data-shapes" |
| 60 | +tokens = ["@dataclass", "NamedTuple", "TypedDict"] |
| 61 | + |
| 62 | +[[confusable_pairs]] |
| 63 | +name = "bound vs unbound methods" |
| 64 | +owner = "bound-and-unbound-methods" |
| 65 | +tokens = ["bound method", "Class.method"] |
| 66 | + |
| 67 | +[[confusable_pairs]] |
| 68 | +name = "yield vs return" |
| 69 | +owner = "generators" |
| 70 | +tokens = ["yield", "return"] |
| 71 | + |
| 72 | +[[confusable_pairs]] |
| 73 | +name = "shallow vs deep copy" |
| 74 | +owner = "copying-collections" |
| 75 | +tokens = ["copy(", "deepcopy("] |
| 76 | + |
| 77 | +[[confusable_pairs]] |
| 78 | +name = "sync vs async functions" |
| 79 | +owner = "async-await" |
| 80 | +tokens = ["async def", "def "] |
| 81 | + |
| 82 | +[broad_surface_tours] |
| 83 | + |
| 84 | +[broad_surface_tours.special-methods] |
| 85 | +required_tokens = [ |
| 86 | + "__init__", "__repr__", "__str__", "__eq__", "__hash__", "__lt__", |
| 87 | + "__len__", "__iter__", "__contains__", "__getitem__", "__setitem__", |
| 88 | + "__call__", "__enter__", "__exit__", "__bool__", |
| 89 | +] |
| 90 | + |
| 91 | +[broad_surface_tours.operators] |
| 92 | +required_tokens = ["+", "==", " is ", " in ", "and", "or", "&", ":="] |
| 93 | + |
| 94 | +[broad_surface_tours.type-hints] |
| 95 | +required_tokens = ["list[", " | ", "Optional", "TypeAlias"] |
| 96 | + |
| 97 | +[broad_surface_tours.testing] |
| 98 | +required_tokens = ["TestCase", "assertEqual", "assertRaises", "setUp"] |
| 99 | + |
| 100 | +[broad_surface_tours.async-await] |
| 101 | +required_tokens = ["async def", "await", "asyncio.run", "asyncio.gather", "async for", "async with"] |
| 102 | + |
| 103 | +[broad_surface_tours.packages] |
| 104 | +required_tokens = ["__init__.py", "from .", "__all__"] |
| 105 | + |
| 106 | +[broad_surface_tours.regular-expressions] |
| 107 | +required_tokens = ["re.match", "re.search", "re.findall", "re.compile", "re.IGNORECASE", "re.sub"] |
| 108 | + |
| 109 | +[broad_surface_tours.literals] |
| 110 | +required_tokens = ["0x", "0b", "_", "f\"", "True", "None"] |
| 111 | + |
| 112 | +[[footguns]] |
| 113 | +name = "Mutable default class attribute" |
| 114 | +owner = "classes" |
| 115 | +broken_tokens = ["items = []"] |
| 116 | +fixed_tokens = ["self.items = []"] |
| 117 | + |
| 118 | +[[footguns]] |
| 119 | +name = "Mutable default function argument" |
| 120 | +owner = "functions" |
| 121 | +broken_tokens = ["=[]", "={}"] |
| 122 | +fixed_tokens = ["= None", "is None"] |
| 123 | + |
| 124 | +[[footguns]] |
| 125 | +name = "Late-binding closure in a loop" |
| 126 | +owner = "closures" |
| 127 | +broken_tokens = ["for ", "lambda"] |
| 128 | +fixed_tokens = ["default", "="] |
| 129 | + |
| 130 | +[[footguns]] |
| 131 | +name = "Integer identity caching" |
| 132 | +owner = "equality-and-identity" |
| 133 | +broken_tokens = [" is "] |
| 134 | +fixed_tokens = ["=="] |
| 135 | + |
| 136 | +[[footguns]] |
| 137 | +name = "Shallow vs deep copy" |
| 138 | +owner = "copying-collections" |
| 139 | +broken_tokens = ["copy("] |
| 140 | +fixed_tokens = ["deepcopy("] |
| 141 | + |
| 142 | +[[footguns]] |
| 143 | +name = "Generator one-pass exhaustion" |
| 144 | +owner = "generators" |
| 145 | +broken_tokens = ["yield"] |
| 146 | +fixed_tokens = ["list("] |
| 147 | + |
| 148 | +[[footguns]] |
| 149 | +name = "Dictionary mutation during iteration" |
| 150 | +owner = "dicts" |
| 151 | +broken_tokens = ["for ", "del "] |
| 152 | +fixed_tokens = ["list(", ".keys("] |
| 153 | + |
| 154 | +[[footguns]] |
| 155 | +name = "Floating-point equality" |
| 156 | +owner = "numbers" |
| 157 | +broken_tokens = ["0.1", "0.2"] |
| 158 | +fixed_tokens = ["isclose", "math"] |
| 159 | + |
| 160 | +[[footguns]] |
| 161 | +name = "bool as a subclass of int" |
| 162 | +owner = "booleans" |
| 163 | +broken_tokens = ["True", "1"] |
| 164 | +fixed_tokens = ["isinstance", "bool"] |
| 165 | + |
| 166 | +[[footguns]] |
| 167 | +name = "Bare except swallowing KeyboardInterrupt" |
| 168 | +owner = "exceptions" |
| 169 | +broken_tokens = ["except:", "except Exception"] |
| 170 | +fixed_tokens = ["except ", " as "] |
| 171 | + |
| 172 | +[paired_pages] |
| 173 | +# Pages whose titles differ only by a suffix or modifier; at least one |
| 174 | +# member of each pair must demonstrate the relationship in a cell. |
| 175 | +pairs = [ |
| 176 | + ["iterators", "iterating-over-iterables"], |
| 177 | + ["iterators", "iterator-vs-iterable"], |
| 178 | + ["generators", "generator-expressions"], |
| 179 | + ["comprehensions", "comprehension-patterns"], |
| 180 | +] |
0 commit comments