One function
Switch in construct/construct
The author described this change as “Switch fixed (bug #357)”. It counts as a record because the check below fails on the code as it stood at 95c7fff40 and passes on 599501980, with nothing else changed between the two runs.
Projectconstruct/construct
Fix saved2017-08-29
Sharing licenceMIT · LICENSE
Change size+5 −11
What the code was meant to do, written into the code itself as a docstring
A conditional branch. Switch will choose the case to follow based on the return value of keyfunc. If no case is matched, and no default value is given, SwitchError will be raised. .. warning:: You can use Embedded(Switch(...)) but not Switch(Embedded(...)). Sames applies to If and IfThenElse macros. :param keyfunc: a context function that returns a key which will choose a case, or a constant :param cases: a dictionary mapping keys to subcons :param default: a default field to use when the key is not found in the cases. if not supplied, an exception will be raised when the key is not found. Pass can be used for do-nothing :param includekey: whether to include the key in the return value of parsing, defualt is False Example::
The change
| 16 | 16 | >>> Switch(this.n, { 1:Byte, 2:Int32ub }).build(5, dict(n=2)) | |
| 17 | 17 | b'\x00\x00\x00\x05' | |
| 18 | 18 | """ | |
| 19 | - | @singleton | |
| 20 | - | class NoDefault(Construct): | |
| 21 | - | def _parse(self, stream, context, path): | |
| 22 | - | raise SwitchError("no default case defined") | |
| 23 | - | def _build(self, obj, stream, context, path): | |
| 24 | - | raise SwitchError("no default case defined") | |
| 25 | - | def _sizeof(self, context, path): | |
| 26 | - | raise SwitchError("no default case defined") | |
| 27 | - | ||
| 28 | 19 | __slots__ = ["subcons", "keyfunc", "cases", "default", "includekey"] | |
| 29 | 20 | def __init__(self, keyfunc, cases, default=NoDefault, includekey=False): | |
| 30 | 21 | super(Switch, self).__init__() | |
| ⋯ | |||
| 32 | 23 | self.cases = cases | |
| 33 | 24 | self.default = default | |
| 34 | 25 | self.includekey = includekey | |
| 35 | - | self.flagbuildnone = all(sc.flagbuildnone for sc in cases.values()) | |
| 36 | - | self.flagembedded = all(sc.flagembedded for sc in cases.values()) | |
| 26 | + | allcases = list(cases.values()) | |
| 27 | + | if default is not NoDefault: | |
| 28 | + | allcases.append(default) | |
| 29 | + | self.flagbuildnone = all(sc.flagbuildnone for sc in allcases) | |
| 30 | + | self.flagembedded = all(sc.flagembedded for sc in allcases) | |
| 37 | 31 | def _parse(self, stream, context, path): | |
| 38 | 32 | key = self.keyfunc(context) if callable(self.keyfunc) else self.keyfunc | |
| 39 | 33 | obj = self.cases.get(key, self.default)._parse(stream, context, path) | |
The check that tells the two apart
fail→pass·tests/test_all.py::TestCore::test_switch_issue_357
Check file tests/test_all.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 it95c7fff4099220fa2563ca79b554b62f6e6c0bde
Broken version dated2017-08-29
Moduleconstruct.core
Units changedSwitch
Fingerprint1d8d1240e4b1ab5d
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 construct/construct
- 2022-09-18Lazy
- 2018-05-05Fix issue #709: Hex() might not always work.
- 2018-04-02VarInt
- 2018-03-03TransformData
- 2017-10-08FIX: Left-shift operator (#406)
- 2017-06-01RawCopy