| 303 | |
| 304 | |
| 305 | def _exclusive_against(*names: str, **kw: Any) -> Callable[[_Fn], _Fn]: |
| 306 | msgs: Dict[str, str] = kw.pop("msgs", {}) |
| 307 | |
| 308 | defaults: Dict[str, str] = kw.pop("defaults", {}) |
| 309 | |
| 310 | getters: List[Tuple[str, operator.attrgetter[Any], Optional[str]]] = [ |
| 311 | (name, operator.attrgetter(name), defaults.get(name, None)) |
| 312 | for name in names |
| 313 | ] |
| 314 | |
| 315 | @util.decorator |
| 316 | def check(fn: _Fn, *args: Any, **kw: Any) -> Any: |
| 317 | # make pylance happy by not including "self" in the argument |
| 318 | # list |
| 319 | self = args[0] |
| 320 | args = args[1:] |
| 321 | for name, getter, default_ in getters: |
| 322 | if getter(self) is not default_: |
| 323 | msg = msgs.get( |
| 324 | name, |
| 325 | "Method %s() has already been invoked on this %s construct" |
| 326 | % (fn.__name__, self.__class__), |
| 327 | ) |
| 328 | raise exc.InvalidRequestError(msg) |
| 329 | return fn(self, *args, **kw) |
| 330 | |
| 331 | return check |
| 332 | |
| 333 | |
| 334 | def _clone(element, **kw): |