coveralls: 
[![Coverage Status](https://coveralls.io/builds/32280388/badge)](https://coveralls.io/builds/32280388)

Coverage decreased (-0.1%) to 99.882% when pulling **eef862701345895f935ad4006eb799ec0670fd61 on develop** into **3c0197bafc8e7946860a8b3cffeea188da944b78 on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/32280389/badge)](https://coveralls.io/builds/32280389)

Coverage decreased (-0.1%) to 99.883% when pulling **eef862701345895f935ad4006eb799ec0670fd61 on develop** into **3c0197bafc8e7946860a8b3cffeea188da944b78 on master**.

diff --git a/.pep8speaks.yml b/.pep8speaks.yml
deleted file mode 100644
index f92b889..0000000
--- a/.pep8speaks.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-scanner:
-    diff_only: True
-    linter: flake8
-
-flake8:
-    max-line-length: 120  # Default is 79 in PEP 8
-    ignore:  # Errors and warnings to ignore
-        - F401
-        - F403
-        - F405
-        - W503
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 400a34a..32bd885 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -21,6 +21,7 @@ Code contributions:
 - (jandelgado)
 - Jonas Irgens Kylling (jkylling)
 - Bruno Rocha (rochacbruno)
+- Noam Graetz (NoamGraetz2)
 
 Suggestions and bug reporting:
 
diff --git a/CHANGES.rst b/CHANGES.rst
index 46f106c..72fc58c 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,14 @@
 Changelog
 =========
 
+
+Version 5.1.0
+-------------
+
+* Adding `dotted` option for `items` function (thanks to ipcoder)
+* Fixing bug in box.set_default where value is dictionary, return the internal value and not detached temporary (thanks to Noam Graetz)
+* Removing warnings on import if optional libraries are missing
+
 Version 5.0.1
 -------------
 
diff --git a/box/__init__.py b/box/__init__.py
index 7e6a976..f128dfc 100644
--- a/box/__init__.py
+++ b/box/__init__.py
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 __author__ = "Chris Griffith"
-__version__ = "5.0.1"
+__version__ = "5.1.0"
 
 from box.box import Box
 from box.box_list import BoxList
diff --git a/box/box.py b/box/box.py
index 9eef453..17cc034 100644
--- a/box/box.py
+++ b/box/box.py
@@ -340,6 +340,15 @@ class Box(dict):
                     keys.add(key)
         return sorted(keys, key=lambda x: str(x))
 
+    def items(self, dotted: Union[bool] = False):
+        if not dotted:
+            return super().items()
+
+        if not self._box_config["box_dots"]:
+            raise BoxError("Cannot return dotted keys as this Box does not have `box_dots` enabled")
+
+        return [(k, self[k]) for k in self.keys(dotted=True)]
+
     def get(self, key, default=NO_DEFAULT):
         if key not in self:
             if default is NO_DEFAULT:
@@ -651,7 +660,7 @@ class Box(dict):
         if isinstance(default, list):
             default = box.BoxList(default, **self.__box_config())
         self[item] = default
-        return default
+        return self[item]
 
     def _safe_attr(self, attr):
         """Convert a key into something that is accessible as an attribute"""
@@ -809,9 +818,6 @@ class Box(dict):
             return cls(data, **box_args)
 
     else:
-        warnings.warn(
-            "yaml is not found in the environment. `to_yaml` and `from_yaml` transforms will not work", BoxWarning
-        )
 
         def to_yaml(
             self,
@@ -875,9 +881,6 @@ class Box(dict):
             return cls(data, **box_args)
 
     else:
-        warnings.warn(
-            "tom is not found in the environment. `to_toml` and `from_toml` transforms will not work", BoxWarning
-        )
 
         def to_toml(self, filename: Union[str, PathLike] = None, encoding: str = "utf-8", errors: str = "strict"):
             raise BoxError('toml is unavailable on this system, please install the "toml" package')
@@ -926,10 +929,6 @@ class Box(dict):
             return cls(data, **box_args)
 
     else:
-        warnings.warn(
-            "msgpack is not found in the environment. " "`to_msgpack` and `from_msgpack` transforms will not work",
-            BoxWarning,
-        )
 
         def to_msgpack(self, filename: Union[str, PathLike] = None, **kwargs):
             raise BoxError('msgpack is unavailable on this system, please install the "msgpack" package')

box.box.Box.setdefault return wrong value if value is dictionary
in short, it should return self[item] instead of default

in details - if the value is dictionary, it is transformed to box internally in the "self[item] = default" call.
in this case, returning 'default' will return a detached empty dictionary that is usless

fixed code should look like:
    def setdefault(self, item, default=None):
        if item in self:
            return self[item]

        if isinstance(default, dict):
            default = self._box_config["box_class"](default, **self.__box_config())
        if isinstance(default, list):
            default = box.BoxList(default, **self.__box_config())
        self[item] = default
        return self[item]

diff --git a/test/test_box.py b/test/test_box.py
index 2c2d805..07affeb 100644
--- a/test/test_box.py
+++ b/test/test_box.py
@@ -289,6 +289,12 @@ class TestBox:
         a.b.b = 4
         assert a.b.b == 4
 
+    def test_set_default_dict(self):
+        a = Box(test_dict)
+        new = a.setdefault("key3", {})
+        new.yy = 8
+        assert a.key3.yy == 8
+
     def test_set_default(self):
         a = Box(test_dict)
 
@@ -661,6 +667,43 @@ class TestBox:
         assert isinstance(list(c.items())[0][1], BoxList)
         d = Box(movie_data)
         assert len(movie_data["movies"].items()) == len(d.movies.items())
+        e = Box(movie_data, box_dots=True)
+        assert sorted(e.items(dotted=True), key=lambda x: x[0]) == sorted(
+            [
+                ("movies.Robin Hood: Men in Tights.Director", "Mel Brooks"),
+                ("movies.Robin Hood: Men in Tights.Stars[0].imdb", "nm0000144"),
+                ("movies.Robin Hood: Men in Tights.Stars[0].name", "Cary Elwes"),
+                ("movies.Robin Hood: Men in Tights.Stars[0].role", "Robin Hood"),
+                ("movies.Robin Hood: Men in Tights.Stars[1].imdb", "nm0507659"),
+                ("movies.Robin Hood: Men in Tights.Stars[1].name", "Richard Lewis"),
+                ("movies.Robin Hood: Men in Tights.Stars[1].role", "Prince John"),
+                ("movies.Robin Hood: Men in Tights.Stars[2].imdb", "nm0715953"),
+                ("movies.Robin Hood: Men in Tights.Stars[2].name", "Roger Rees"),
+                ("movies.Robin Hood: Men in Tights.Stars[2].role", "Sheriff of Rottingham"),
+                ("movies.Robin Hood: Men in Tights.Stars[3].imdb", "nm0001865"),
+                ("movies.Robin Hood: Men in Tights.Stars[3].name", "Amy Yasbeck"),
+                ("movies.Robin Hood: Men in Tights.Stars[3].role", "Marian"),
+                ("movies.Robin Hood: Men in Tights.imdb_stars", 6.7),
+                ("movies.Robin Hood: Men in Tights.length", 104),
+                ("movies.Robin Hood: Men in Tights.rating", "PG-13"),
+                ("movies.Spaceballs.Director", "Mel Brooks"),
+                ("movies.Spaceballs.Stars[0].imdb", "nm0000316"),
+                ("movies.Spaceballs.Stars[0].name", "Mel Brooks"),
+                ("movies.Spaceballs.Stars[0].role", "President Skroob"),
+                ("movies.Spaceballs.Stars[1].imdb", "nm0001006"),
+                ("movies.Spaceballs.Stars[1].name", "John Candy"),
+                ("movies.Spaceballs.Stars[1].role", "Barf"),
+                ("movies.Spaceballs.Stars[2].imdb", "nm0001548"),
+                ("movies.Spaceballs.Stars[2].name", "Rick Moranis"),
+                ("movies.Spaceballs.Stars[2].role", "Dark Helmet"),
+                ("movies.Spaceballs.imdb_stars", 7.1),
+                ("movies.Spaceballs.length", 96),
+                ("movies.Spaceballs.rating", "PG"),
+            ],
+            key=lambda x: x[0],
+        )
+        with pytest.raises(BoxError):
+            Box(box_dots=False).items(dotted=True)
 
     def test_get(self):
         bx = Box()

pip install -e .[all]
parse_log_pytest
requirements.txt
pytest pytest-cov
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
coverage==7.8.0
exceptiongroup==1.2.2
iniconfig==2.1.0
msgpack==1.1.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytest-cov==6.0.0
-e git+https://github.com/cdgriffith/Box.git@3c0197bafc8e7946860a8b3cffeea188da944b78#egg=python_box
ruamel.yaml==0.18.10
ruamel.yaml.clib==0.2.12
toml==0.10.2
tomli==2.2.1

name: Box
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - msgpack==1.1.0
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - ruamel-yaml==0.18.10
      - ruamel-yaml-clib==0.2.12
      - toml==0.10.2
      - tomli==2.2.1
prefix: /opt/conda/envs/Box

test/test_box.py::TestBox::test_set_default_dict test/test_box.py::TestBox::test_items
test/test_box.py::TestBox::test_to_yaml_basic test/test_box.py::TestBox::test_to_yaml_file test/test_box.py::TestBox::test_from_yaml_file test/test_box.py::TestBox::test_from_yaml test/test_box.py::TestBox::test_bad_from_yaml test/test_box.py::TestBox::test_parameter_pass_through
test/test_box.py::TestBox::test_safe_attrs test/test_box.py::TestBox::test_camel_killer test/test_box.py::TestBox::test_recursive_tuples test/test_box.py::TestBox::test_box test/test_box.py::TestBox::test_box_modify_at_depth test/test_box.py::TestBox::test_error_box test/test_box.py::TestBox::test_box_from_dict test/test_box.py::TestBox::test_box_from_bad_dict test/test_box.py::TestBox::test_basic_box test/test_box.py::TestBox::test_protected_box_methods test/test_box.py::TestBox::test_bad_args test/test_box.py::TestBox::test_box_inits test/test_box.py::TestBox::test_bad_inits test/test_box.py::TestBox::test_create_subdicts test/test_box.py::TestBox::test_to_json_basic test/test_box.py::TestBox::test_dir test/test_box.py::TestBox::test_update test/test_box.py::TestBox::test_merge_update test/test_box.py::TestBox::test_auto_attr test/test_box.py::TestBox::test_set_default test/test_box.py::TestBox::test_from_json_file test/test_box.py::TestBox::test_from_json test/test_box.py::TestBox::test_bad_from_json test/test_box.py::TestBox::test_conversion_box test/test_box.py::TestBox::test_frozen test/test_box.py::TestBox::test_hashing test/test_box.py::TestBox::test_config test/test_box.py::TestBox::test_default_box test/test_box.py::TestBox::test_default_box_none_transforms test/test_box.py::TestBox::test_camel_killer_box test/test_box.py::TestBox::test_default_and_camel_killer_box test/test_box.py::TestBox::test_box_modify_tuples test/test_box.py::TestBox::test_box_set_attribs test/test_box.py::TestBox::test_functional_data test/test_box.py::TestBox::test_functional_spaceballs test/test_box.py::TestBox::test_circular_references test/test_box.py::TestBox::test_to_multiline test/test_box.py::TestBox::test_from_multiline test/test_box.py::TestBox::test_duplicate_errors test/test_box.py::TestBox::test_copy test/test_box.py::TestBox::test_custom_key_errors test/test_box.py::TestBox::test_pickle test/test_box.py::TestBox::test_pickle_default_box test/test_box.py::TestBox::test_conversion_dup_only test/test_box.py::TestBox::test_values test/test_box.py::TestBox::test_get test/test_box.py::TestBox::test_get_default_box test/test_box.py::TestBox::test_inheritance_copy test/test_box.py::TestBox::test_inheritance test/test_box.py::TestBox::test_underscore_removal test/test_box.py::TestBox::test_is_in test/test_box.py::TestBox::test_through_queue test/test_box.py::TestBox::test_update_with_integer test/test_box.py::TestBox::test_get_box_config test/test_box.py::TestBox::test_pop test/test_box.py::TestBox::test_pop_items test/test_box.py::TestBox::test_iter test/test_box.py::TestBox::test_revered test/test_box.py::TestBox::test_clear test/test_box.py::TestBox::test_bad_recursive test/test_box.py::TestBox::test_dots test/test_box.py::TestBox::test_unicode test/test_box.py::TestBox::test_camel_killer_hashables test/test_box.py::TestBox::test_intact_types_dict test/test_box.py::TestBox::test_delete_attributes test/test_box.py::TestBox::test_add_boxes test/test_box.py::TestBox::test_iadd_boxes test/test_box.py::TestBox::test_radd_boxes test/test_box.py::TestBox::test_or_boxes test/test_box.py::TestBox::test_ior_boxes test/test_box.py::TestBox::test_ror_boxes test/test_box.py::TestBox::test_type_recast test/test_box.py::TestBox::test_box_dots test/test_box.py::TestBox::test_toml test/test_box.py::TestBox::test_sub test/test_box.py::TestBox::test_sub_with_non_dict test/test_box.py::TestBox::test_sub_with_frozen_box test/test_box.py::TestBox::test_no_key_error_pop test/test_box.py::TestBox::test_key_error_popitem test/test_box.py::TestBox::test_msgpack_strings test/test_box.py::TestBox::test_msgpack_strings_no_strick_keys test/test_box.py::TestBox::test_msgpack_files test/test_box.py::TestBox::test_msgpack_no_input test/test_box.py::TestBox::test_value_view test/test_box.py::TestBox::test_key_view test/test_box.py::TestBox::test_item_view test/test_box.py::TestBox::test_box_propagation test/test_box.py::TestBox::test_box_safe_references test/test_box.py::TestBox::test_default_box_restricted_calls
.pep8speaks.yml AUTHORS.rst box/box.py CHANGES.rst box/__init__.py
.pep8speaks.yml AUTHORS.rst box/box.py CHANGES.rst box/__init__.py