On Tue, Oct 8, 2024 at 8:16 AM Bartosz Golaszewski <brgl@xxxxxxxx> wrote: > > > Ok, so I don't really understand what is happening here. We're going > to re-assign _chip in every function? What happens to cast() if _chip > IS None? In this scenario, self._chip cannot be None. The self._check_closed() guard ensures this, however, type checkers (at least mypy) cannot infer that from the current code pattern. `cast` is informing the type checker that past this point, self._chip should not be considered as None and it's safe to reference attributes off the object This seemed like the cleanest alternative, though others are: * use a local variable for the cast result. This may be less confusing but incurs more changed lines self._check_closed() chip = cast(_ext.Chip, self._chip) return chip.path * use asserts. These aren't always enforced during runtime so we cannot replace _check_closed but it does inform the type checker that it can narrow the type. Using both is ok, just slightly redundant. self._check_closed() assert self._chip is not None return self._chip.path * add a `if self._chip is None` check that duplicates _check_closed (or replace it completely) * other "creative" solutions like a wrapper that returns a Chip or throws an exception if it's None. def _chip_or_exc(self) -> Chip: if self._chip is None: raise Exception return self._chip chip = self._chip_or_exc() return chip.path > > Bart