One function
make_sentinel in mahmoud/boltons
The author described this change as “fix Sentinel module logic, enabling pickling of Sentinels, fixes #285”. It counts as a record because the check below fails on the code as it stood at 3c1d3987a and passes on 16a258e37, with nothing else changed between the two runs.
Projectmahmoud/boltons
Fix saved2021-05-16
Sharing licenceBSD-2-Clause · LICENSE
Change size+11 −1
What the code was meant to do, written into the code itself as a docstring
Creates and returns a new **instance** of a new class, suitable for usage as a "sentinel", a kind of singleton often used to indicate a value is missing when `None` is a valid input. Args: name (str): Name of the Sentinel var_name (str): Set this name to the name of the variable in its respective module enable pickleability. The most common use cases here in boltons are as default values for optional function arguments, partly because of its less-confusing appearance in automatically generated documentation. Sentinels also function well as placeholders in queues and linked lists. .. note:: By design, additional calls to `make_sentinel` with the same values will not produce equivalent objects.
The change
| 6 | 6 | Args: | |
| 7 | 7 | name (str): Name of the Sentinel | |
| 8 | 8 | var_name (str): Set this name to the name of the variable in | |
| 9 | - | its respective module enable pickleability. | |
| 9 | + | its respective module enable pickleability. Note: | |
| 10 | + | pickleable sentinels should be global constants at the top | |
| 11 | + | level of their module. | |
| 10 | 12 | ||
| 11 | 13 | >>> make_sentinel(var_name='_MISSING') | |
| 12 | 14 | _MISSING | |
| ⋯ | |||
| 37 | 39 | if self.var_name: | |
| 38 | 40 | return self.var_name | |
| 39 | 41 | return '%s(%r)' % (self.__class__.__name__, self.name) | |
| 42 | + | ||
| 40 | 43 | if var_name: | |
| 41 | 44 | def __reduce__(self): | |
| 42 | 45 | return self.var_name | |
| ⋯ | |||
| 45 | 48 | return False | |
| 46 | 49 | ||
| 47 | 50 | __bool__ = __nonzero__ | |
| 51 | + | ||
| 52 | + | if var_name: | |
| 53 | + | module = getattr(sys._getframe(1), '__module__', None) | |
| 54 | + | if not module: | |
| 55 | + | raise ValueError('Pickleable sentinel objects (with var_name) can only' | |
| 56 | + | ' be created from top-level module scopes') | |
| 57 | + | Sentinel.__module__ = module | |
| 48 | 58 | ||
| 49 | 59 | return Sentinel() | |
The check that tells the two apart
fail→pass·tests/test_typeutils.py::test_sentinel_pickle
Check file tests/test_typeutils.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.
Origin and history
The code before it3c1d3987a91fe2d48ee723dda6ca0bd3fb7f94a9
Broken version dated2021-05-16
Moduleboltons.typeutils
Units changedmake_sentinel
Fingerprint987f03c477a8ef3f
Checked2026-08-18 by goldset/0.1
Every field above is generated by our program. None of it is written by hand.
Other bugs found in mahmoud/boltons
- 2026-08-06Bits
- 2026-08-06JSONLIterator
- 2026-08-06tableutils: fix Table.to_text crashes on degenerate tables and headers
- 2026-07-18backoff_iter
- 2026-07-17singularize
- 2026-07-17fix(fileutils): accept os.PathLike in AtomicSaver