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

Coverage decreased (-0.2%) to 95.795% when pulling **c0fe7ce85b40ed778e86cbe43333a8e21d0115f8 on 230_default_data_object** into **9e1127a7ec8a811ae6cd7fb98adc358308a17103 on master**.

diff --git a/HISTORY.rst b/HISTORY.rst
index 4100c7e..62ac03e 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,25 +2,6 @@
 History
 =======
 
-3.0.0b1 (unreleased)
---------------------
-
-Features:
-
-* Support marshmallow 3 (see #154).
-* All field parameters beginning with ``"marshmallow_"`` are passed to the
-  marshmallow schema, rather than only a given list of known parameters.
-  (see #228)
-
-Other changes:
-
-* *Backwards-incompatible*: Drop support for marshmallow 2. See marshmallow
-  upgrading guide for a comprehensive list of changes. (see #154)
-* *Backwards-incompatible*: ``StrictDateTimeField`` is removed as marshmallow
-  now provides ``NaiveDateTimeField`` and ``AwareDateTimeField``. (see #154)
-* *Backwards-incompatible*: ``default`` shall now be provided in deserialized
-  form. (see #154)
-
 2.2.0 (2019-12-18)
 ------------------
 
diff --git a/umongo/fields.py b/umongo/fields.py
index 950a4cd..79d8c04 100644
--- a/umongo/fields.py
+++ b/umongo/fields.py
@@ -53,6 +53,19 @@ __all__ = (
 
 class DictField(BaseField, ma_fields.Dict):
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        def cast_value_or_callable(value):
+            if value is missing:
+                return missing
+            if callable(value):
+                return lambda: Dict(value())
+            return Dict(value)
+
+        self.default = cast_value_or_callable(self.default)
+        self.missing = cast_value_or_callable(self.missing)
+
     def _deserialize(self, value, attr, data, **kwargs):
         value = super()._deserialize(value, attr, data, **kwargs)
         return Dict(value)
@@ -75,6 +88,19 @@ class DictField(BaseField, ma_fields.Dict):
 
 class ListField(BaseField, ma_fields.List):
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        def cast_value_or_callable(inner, value):
+            if value is missing:
+                return missing
+            if callable(value):
+                return lambda: List(inner, value())
+            return List(inner, value)
+
+        self.default = cast_value_or_callable(self.inner, self.default)
+        self.missing = cast_value_or_callable(self.inner, self.missing)
+
     def _deserialize(self, value, attr, data, **kwargs):
         ret = List(self.inner, super()._deserialize(value, attr, data, **kwargs))
         return ret

DictField / ListField: how to pass dict / list as default?
Since #154, default values must be passed in deserialized form for consistency with marshmallow 3.

One can't write this anymore:

```py
list_field = ListField(IntField, default=list)
```

One must now write

```py
from umongo.data_objects import List
list_field = ListField(IntField, default=List)
```

Not ideal.

Shall we still take default values in serialized form in umongo even if it is not consistent with marshmallow 3? Is there another way to cast the default value in these specific cases?

Edit: in fact, the workaround above doesn't work, so it is worse than not ideal, it is a blocker.
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 9577717..21c5ff9 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -275,6 +275,33 @@ class TestFields(BaseTest):
         d4.from_mongo({'in_mongo_dict': None})
         assert d4.get('dict') is None
 
+    def test_dict_default(self):
+
+        class MySchema(Schema):
+            # Passing a mutable as default is a bad idea in real life
+            d_dict = fields.DictField(default={'1': 1, '2': 2})
+            c_dict = fields.DictField(default=lambda: {'1': 1, '2': 2})
+
+        MyDataProxy = data_proxy_factory('My', MySchema())
+        d = MyDataProxy()
+        assert d.to_mongo() == {
+            'd_dict': {'1': 1, '2': 2},
+            'c_dict': {'1': 1, '2': 2},
+        }
+        assert isinstance(d.get('d_dict'), Dict)
+        assert isinstance(d.get('c_dict'), Dict)
+        d.get('d_dict')['3'] = 3
+        d.get('c_dict')['3'] = 3
+
+        d.delete('d_dict')
+        d.delete('c_dict')
+        assert d.to_mongo() == {
+            'd_dict': {'1': 1, '2': 2},
+            'c_dict': {'1': 1, '2': 2},
+        }
+        assert isinstance(d.get('d_dict'), Dict)
+        assert isinstance(d.get('c_dict'), Dict)
+
     def test_list(self):
 
         class MySchema(Schema):
@@ -360,6 +387,36 @@ class TestFields(BaseTest):
             d3._data.get('in_mongo_list')
         ) == '<object umongo.data_objects.List([])>'
 
+    def test_list_default(self):
+
+        class MySchema(Schema):
+            d_list = fields.ListField(fields.IntField(), default=(1, 2, 3))
+            c_list = fields.ListField(fields.IntField(), default=lambda: (1, 2, 3))
+
+        MyDataProxy = data_proxy_factory('My', MySchema())
+        d = MyDataProxy()
+        assert d.to_mongo() == {
+            'd_list': [1, 2, 3],
+            'c_list': [1, 2, 3],
+        }
+        assert isinstance(d.get('d_list'), List)
+        assert isinstance(d.get('c_list'), List)
+        d.get('d_list').append(4)
+        d.get('c_list').append(4)
+        assert d.to_mongo(update=True) == {
+            '$set': {'c_list': [1, 2, 3, 4], 'd_list': [1, 2, 3, 4]}}
+
+        d.delete('d_list')
+        d.delete('c_list')
+        assert d.to_mongo() == {
+            'd_list': [1, 2, 3],
+            'c_list': [1, 2, 3],
+        }
+        assert isinstance(d.get('d_list'), List)
+        assert isinstance(d.get('c_list'), List)
+        assert d.to_mongo(update=True) == {
+            '$set': {'c_list': [1, 2, 3], 'd_list': [1, 2, 3]}}
+
     def test_complex_list(self):
 
         @self.instance.register

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov
apt-get update apt-get install -y gcc
3.7
requirements_dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
Babel==2.14.0
bump2version==1.0.1
bumpversion==0.6.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
charset-normalizer==3.4.1
coverage==7.2.7
distlib==0.3.9
dnspython==2.3.0
docutils==0.17.1
exceptiongroup==1.2.2
filelock==3.12.2
flake8==5.0.4
idna==3.10
imagesize==1.4.1
importlib-metadata==4.2.0
iniconfig==2.0.0
Jinja2==3.1.6
MarkupSafe==2.1.5
marshmallow==3.19.0
mccabe==0.7.0
packaging==24.0
platformdirs==2.6.2
pluggy==1.2.0
py==1.11.0
pycodestyle==2.9.1
pyflakes==2.5.0
Pygments==2.17.2
pymongo==4.7.3
pytest==7.4.4
pytest-cov==4.1.0
pytz==2025.2
requests==2.31.0
six==1.17.0
snowballstemmer==2.2.0
Sphinx==4.3.2
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
tomli==2.0.1
tox==3.28.0
typing_extensions==4.7.1
-e git+https://github.com/Scille/umongo.git@3c546921f4c9fb8bc686329beac903bf86597c5d#egg=umongo
urllib3==2.0.7
virtualenv==20.16.2
zipp==3.15.0

name: umongo
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
  - certifi=2022.12.7=py37h06a4308_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=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - babel==2.14.0
      - bump2version==1.0.1
      - bumpversion==0.6.0
      - charset-normalizer==3.4.1
      - coverage==7.2.7
      - distlib==0.3.9
      - dnspython==2.3.0
      - docutils==0.17.1
      - exceptiongroup==1.2.2
      - filelock==3.12.2
      - flake8==5.0.4
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==4.2.0
      - iniconfig==2.0.0
      - jinja2==3.1.6
      - markupsafe==2.1.5
      - marshmallow==3.19.0
      - mccabe==0.7.0
      - packaging==24.0
      - platformdirs==2.6.2
      - pluggy==1.2.0
      - py==1.11.0
      - pycodestyle==2.9.1
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pymongo==4.7.3
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytz==2025.2
      - requests==2.31.0
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==4.3.2
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - tomli==2.0.1
      - tox==3.28.0
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - virtualenv==20.16.2
      - zipp==3.15.0
prefix: /opt/conda/envs/umongo

tests/test_fields.py::TestFields::test_dict_default tests/test_fields.py::TestFields::test_list_default
tests/test_fields.py::TestRequired::test_required tests/test_fields.py::TestRequired::test_required_nested tests/test_fields.py::TestFields::test_basefields tests/test_fields.py::TestFields::test_datetime tests/test_fields.py::TestFields::test_aware_datetime tests/test_fields.py::TestFields::test_date tests/test_fields.py::TestFields::test_dict tests/test_fields.py::TestFields::test_list tests/test_fields.py::TestFields::test_complex_list tests/test_fields.py::TestFields::test_objectid tests/test_fields.py::TestFields::test_reference tests/test_fields.py::TestFields::test_reference_lazy tests/test_fields.py::TestFields::test_generic_reference tests/test_fields.py::TestFields::test_decimal
HISTORY.rst umongo/fields.py
HISTORY.rst umongo/fields.py