Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions datafiles/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
from functools import reduce
from glob import iglob
from pathlib import Path
from typing import TYPE_CHECKING, Iterator, Optional
from typing import TYPE_CHECKING, Any, Iterator, Optional

import log
from parse import parse
from ruamel.yaml.error import MarkedYAMLError

from . import hooks, model
from .converters import map_type

if TYPE_CHECKING:
from .model import Model
Expand Down Expand Up @@ -150,7 +151,30 @@ def all(self, *, _exclude: str = "") -> Iterator[Model]:
continue

names = [name.removeprefix("self.") for name in result.named]
yield self.get(**dict(zip(names, values)))
yield self.get(**dict(zip(names, self._coerce_values(names, values))))

def _coerce_values(self, names: list[str], values: list[str]) -> list[Any]:
"""Coerce path-derived string values to their declared field types.

``all()`` extracts placeholder values (e.g. the primary key) from the
filename as strings. Unlike the other attributes, these are not loaded
from the file contents, so they never pass through the field's
converter. Convert them here so ``Model.objects.all()`` yields instances
whose path fields match their declared types (see issue #147).
"""
fields = {
field.name: field
for field in dataclasses.fields(self.model)
if field.init
}
coerced = []
for name, value in zip(names, values):
field = fields.get(name)
if field is not None:
converter = map_type(field.type, name=name) # type: ignore
value = converter.to_python_value(value)
coerced.append(value)
return coerced

def filter(self, *, _exclude: str = "", **query):
for item in self.all(_exclude=_exclude):
Expand Down
1 change: 0 additions & 1 deletion tests/test_orm_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ class Bar:
expect(bar.nested.value) == 2


@pytest.mark.xfail(reason="https://github.com/jacebrowning/datafiles/issues/147")
def test_values_are_filled_from_disk(expect):
InventoryItem.objects.get_or_create(42, "Things", 0.99)

Expand Down