|
10 | 10 | import warnings |
11 | 11 | from keyword import iskeyword |
12 | 12 | from os import PathLike |
13 | | -from typing import Any, Dict, Generator, List, Optional, Tuple, Type, Union |
| 13 | +from typing import Any, Dict, Generator, List, Optional, Tuple, Type, Union, Literal |
14 | 14 | from inspect import signature |
15 | 15 |
|
16 | 16 | try: |
17 | 17 | from typing import Callable, Iterable, Mapping |
18 | 18 | except ImportError: |
19 | 19 | from collections.abc import Callable, Iterable, Mapping |
20 | 20 |
|
21 | | -try: |
22 | | - from IPython import get_ipython |
23 | | -except ImportError: |
24 | | - ipython = False |
25 | | -else: |
26 | | - ipython = True if get_ipython() else False |
27 | 21 |
|
28 | 22 | import box |
29 | 23 | from box.converters import ( |
|
56 | 50 | NO_NAMESPACE = object() |
57 | 51 |
|
58 | 52 |
|
| 53 | +def _is_ipython(): |
| 54 | + try: |
| 55 | + from IPython import get_ipython |
| 56 | + except ImportError: |
| 57 | + ipython = False |
| 58 | + else: |
| 59 | + ipython = True if get_ipython() else False |
| 60 | + |
| 61 | + return ipython |
| 62 | + |
| 63 | + |
59 | 64 | def _exception_cause(e): |
60 | 65 | """ |
61 | 66 | Unwrap BoxKeyError and BoxValueError errors to their cause. |
@@ -201,7 +206,7 @@ def __new__( |
201 | 206 | box_recast: Optional[Dict] = None, |
202 | 207 | box_dots: bool = False, |
203 | 208 | box_class: Optional[Union[Dict, Type["Box"]]] = None, |
204 | | - box_namespace: Tuple[str, ...] = (), |
| 209 | + box_namespace: Union[Tuple[str, ...], Literal[False]] = (), |
205 | 210 | **kwargs: Any, |
206 | 211 | ): |
207 | 212 | """ |
@@ -248,7 +253,7 @@ def __init__( |
248 | 253 | box_recast: Optional[Dict] = None, |
249 | 254 | box_dots: bool = False, |
250 | 255 | box_class: Optional[Union[Dict, Type["Box"]]] = None, |
251 | | - box_namespace: Tuple[str, ...] = (), |
| 256 | + box_namespace: Union[Tuple[str, ...], Literal[False]] = (), |
252 | 257 | **kwargs: Any, |
253 | 258 | ): |
254 | 259 | super().__init__() |
@@ -380,7 +385,7 @@ def __hash__(self): |
380 | 385 | return hashing |
381 | 386 | raise BoxTypeError('unhashable type: "Box"') |
382 | 387 |
|
383 | | - def __dir__(self): |
| 388 | + def __dir__(self) -> List[str]: |
384 | 389 | items = set(super().__dir__()) |
385 | 390 | # Only show items accessible by dot notation |
386 | 391 | for key in self.keys(): |
@@ -483,7 +488,7 @@ def __setstate__(self, state): |
483 | 488 | self.__dict__.update(state) |
484 | 489 |
|
485 | 490 | def __get_default(self, item, attr=False): |
486 | | - if ipython and item in ("getdoc", "shape"): |
| 491 | + if item in ("getdoc", "shape") and _is_ipython(): |
487 | 492 | return None |
488 | 493 | default_value = self._box_config["default_box_attr"] |
489 | 494 | if default_value in (self._box_config["box_class"], dict): |
@@ -589,6 +594,12 @@ def __getitem__(self, item, _ignore_default=False): |
589 | 594 | if item == "_box_config": |
590 | 595 | cause = _exception_cause(err) |
591 | 596 | raise BoxKeyError("_box_config should only exist as an attribute and is never defaulted") from cause |
| 597 | + if isinstance(item, slice): |
| 598 | + # In Python 3.12 this changes to a KeyError instead of TypeError |
| 599 | + new_box = self._box_config["box_class"](**self.__box_config()) |
| 600 | + for x in list(super().keys())[item.start : item.stop : item.step]: |
| 601 | + new_box[x] = self[x] |
| 602 | + return new_box |
592 | 603 | if self._box_config["box_dots"] and isinstance(item, str) and ("." in item or "[" in item): |
593 | 604 | try: |
594 | 605 | first_item, children = _parse_box_dots(self, item) |
@@ -823,7 +834,7 @@ def convert_and_set(k, v): |
823 | 834 | # in the `converted` box_config set |
824 | 835 | v = self._box_config["box_class"](v, **self.__box_config(extra_namespace=k)) |
825 | 836 | if k in self and isinstance(self[k], dict): |
826 | | - self[k].merge_update(v) |
| 837 | + self[k].merge_update(v, box_merge_lists=merge_type) |
827 | 838 | return |
828 | 839 | if isinstance(v, list) and not intact_type: |
829 | 840 | v = box.BoxList(v, **self.__box_config(extra_namespace=k)) |
|
0 commit comments