| 4292 | ) |
| 4293 | |
| 4294 | def _interpret_range( |
| 4295 | self, |
| 4296 | range_: typing_Tuple[Optional[_IntOrRange], Optional[_IntOrRange]], |
| 4297 | ) -> typing_Tuple[_IntOrRange, _IntOrRange]: |
| 4298 | if not isinstance(range_, tuple) or len(range_) != 2: |
| 4299 | raise exc.ArgumentError("2-tuple expected for range/rows") |
| 4300 | |
| 4301 | r0, r1 = range_ |
| 4302 | |
| 4303 | lower: _IntOrRange |
| 4304 | upper: _IntOrRange |
| 4305 | |
| 4306 | if r0 is None: |
| 4307 | lower = RANGE_UNBOUNDED |
| 4308 | elif isinstance(r0, _OverRange): |
| 4309 | lower = r0 |
| 4310 | else: |
| 4311 | try: |
| 4312 | lower = int(r0) |
| 4313 | except ValueError as err: |
| 4314 | raise exc.ArgumentError( |
| 4315 | "Integer or None expected for range value" |
| 4316 | ) from err |
| 4317 | else: |
| 4318 | if lower == 0: |
| 4319 | lower = RANGE_CURRENT |
| 4320 | |
| 4321 | if r1 is None: |
| 4322 | upper = RANGE_UNBOUNDED |
| 4323 | elif isinstance(r1, _OverRange): |
| 4324 | upper = r1 |
| 4325 | else: |
| 4326 | try: |
| 4327 | upper = int(r1) |
| 4328 | except ValueError as err: |
| 4329 | raise exc.ArgumentError( |
| 4330 | "Integer or None expected for range value" |
| 4331 | ) from err |
| 4332 | else: |
| 4333 | if upper == 0: |
| 4334 | upper = RANGE_CURRENT |
| 4335 | |
| 4336 | return lower, upper |
| 4337 | |
| 4338 | if not TYPE_CHECKING: |
| 4339 | |