From e8fc6fd7be8ab15897facfcfa5cc91982849958b Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 26 Dec 2019 17:09:12 -0500 Subject: [PATCH] Update failure reason --- .gitignore | 1 + CHANGELOG.md | 1 + datafiles/manager.py | 38 +++++++++++++-------------- datafiles/tests/test_manager.py | 12 ++++----- docs/api/manager.md | 46 ++++++++++++++++----------------- pyproject.toml | 2 +- tests/test_orm_usage.py | 2 +- 7 files changed, 52 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index a2c6f4bd..7df91169 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.egg-info __pycache__ .ipynb_checkpoints +setup.py # Temporary OS files Icon* diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a048a5d..e72dc487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 0.6 (unreleased) - Added a registration system for custom formatter classes. +- Fixed loading of missing attribute from disk for ORM methods. # 0.5.1 (2019-11-14) diff --git a/datafiles/manager.py b/datafiles/manager.py index 725e6e9c..e73a46c5 100644 --- a/datafiles/manager.py +++ b/datafiles/manager.py @@ -23,20 +23,19 @@ Missing = dataclasses._MISSING_TYPE +class HasDatafile(Protocol): + datafile: Mapper + + +class Splats: + def __getattr__(self, name): + return '*' + + class Manager: def __init__(self, cls): self.model = cls - def all(self) -> Iterator[HasDatafile]: - root = Path(inspect.getfile(self.model)).parent - pattern = str(root / self.model.Meta.datafile_pattern) - splatted = pattern.format(self=Splats()) - log.info(f'Finding files matching pattern: {splatted}') - for filename in iglob(splatted): - log.debug(f'Found matching path: {filename}') - results = parse(pattern, filename) - yield self.get(*results.named.values()) - def get(self, *args, **kwargs) -> HasDatafile: fields = dataclasses.fields(self.model) missing_args = [Missing] * (len(fields) - len(args) - len(kwargs)) @@ -62,6 +61,16 @@ def get_or_create(self, *args, **kwargs) -> HasDatafile: log.info(f"File not found, creating '{self.model.__name__}' object") return self.model(*args, **kwargs) + def all(self) -> Iterator[HasDatafile]: + root = Path(inspect.getfile(self.model)).parent + pattern = str(root / self.model.Meta.datafile_pattern) + splatted = pattern.format(self=Splats()) + log.info(f'Finding files matching pattern: {splatted}') + for filename in iglob(splatted): + log.debug(f'Found matching path: {filename}') + results = parse(pattern, filename) + yield self.get(*results.named.values()) + def filter(self, **query): for item in self.all(): match = True @@ -70,12 +79,3 @@ def filter(self, **query): match = False if match: yield item - - -class HasDatafile(Protocol): - datafile: Mapper - - -class Splats: - def __getattr__(self, name): - return '*' diff --git a/datafiles/tests/test_manager.py b/datafiles/tests/test_manager.py index 910aa509..22a4465e 100644 --- a/datafiles/tests/test_manager.py +++ b/datafiles/tests/test_manager.py @@ -21,12 +21,6 @@ def manager(): model = create_model(MyClass, pattern='files/{self.foo}.yml') return Manager(model) - def describe_all(): - @patch('datafiles.mapper.Mapper.exists', False) - def when_no_files_exist(expect, manager): - items = list(manager.all()) - expect(items) == [] - def describe_get_or_none(): @patch('datafiles.mapper.Mapper.load') @patch('datafiles.mapper.Mapper.exists', True) @@ -55,6 +49,12 @@ def when_file_missing(mock_save, expect, manager): expect(manager.get_or_create(foo=1, bar=2)) == MyClass(foo=1, bar=2) expect(mock_save.called) == True + def describe_all(): + @patch('datafiles.mapper.Mapper.exists', False) + def when_no_files_exist(expect, manager): + items = list(manager.all()) + expect(items) == [] + def describe_filter(): @patch('datafiles.mapper.Mapper.exists', False) def when_no_files_exist(expect, manager): diff --git a/docs/api/manager.md b/docs/api/manager.md index 49fe298b..7e12e8c0 100644 --- a/docs/api/manager.md +++ b/docs/api/manager.md @@ -14,29 +14,6 @@ class MyModel: Many of the following examples are also shown in this [Jupyter Notebook](https://github.com/jacebrowning/datafiles/blob/develop/notebooks/manager_api.ipynb). -# `all()` - -Iterate over all objects matching the pattern: - -```python ->>> generator = MyModel.objects.all() ->>> list(generator) -[] -``` - -```python ->>> m1 = MyModel('foo') ->>> m2 = MyModel('bar', 42) -``` - -```python ->>> for m in MyModel.objects.all(): -... print(m) -... -MyModel(my_key='foo' my_value=0) -MyModel(my_key='bar', my_value=42) -``` - # `get_or_none()` Instantiate an object from an existing file or return `None` if no matching file exists: @@ -73,6 +50,29 @@ MyModel(my_key='foo', my_value=42) MyModel(my_key='bar', my_value=0) ``` +# `all()` + +Iterate over all objects matching the pattern: + +```python +>>> generator = MyModel.objects.all() +>>> list(generator) +[] +``` + +```python +>>> m1 = MyModel('foo') +>>> m2 = MyModel('bar', 42) +``` + +```python +>>> for m in MyModel.objects.all(): +... print(m) +... +MyModel(my_key='foo' my_value=0) +MyModel(my_key='bar', my_value=42) +``` + # `filter()` Iterate all objects matching the pattern with additional required attribute values: diff --git a/pyproject.toml b/pyproject.toml index bb54ce33..30f51750 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "datafiles" -version = "0.6b2" +version = "0.6b3" description = "File-based ORM for dataclasses." license = "MIT" diff --git a/tests/test_orm_usage.py b/tests/test_orm_usage.py index 2478485d..aaba1842 100644 --- a/tests/test_orm_usage.py +++ b/tests/test_orm_usage.py @@ -71,7 +71,7 @@ class Bar: expect(bar.nested.value) == 2 -@pytest.mark.xfail(reason='https://github.com/jacebrowning/datafiles/issues/139') +@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)