Skip to content

Commit

Permalink
Handle malformed YAML
Browse files Browse the repository at this point in the history
  • Loading branch information
jacebrowning committed Jun 6, 2020
1 parent 3960089 commit a0b617c
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 44 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
@@ -1,6 +1,7 @@
# 0.10 (beta)

- Added support for recursively matching arbitrary depth paths of files.
- Fixed `AttributeError` when attempting to load malformed YAML files.

# 0.9 (2020-04-13)

Expand Down
25 changes: 14 additions & 11 deletions datafiles/formats.py
Expand Up @@ -5,7 +5,7 @@
from contextlib import suppress
from io import StringIO
from pathlib import Path
from typing import IO, Any, Dict, List
from typing import IO, Dict, List

import log

Expand All @@ -30,7 +30,7 @@ def extensions(cls) -> List[str]:

@classmethod
@abstractmethod
def deserialize(cls, file_object: IO[Any]) -> Dict:
def deserialize(cls, file_object: IO) -> Dict:
raise NotImplementedError

@classmethod
Expand All @@ -48,7 +48,7 @@ def extensions(cls):

@classmethod
def deserialize(cls, file_object):
return json.load(file_object) or {}
return json.load(file_object)

@classmethod
def serialize(cls, data):
Expand All @@ -66,7 +66,7 @@ def extensions(cls):
def deserialize(cls, file_object):
import tomlkit

return tomlkit.loads(file_object.read()) or {}
return tomlkit.loads(file_object.read())

@classmethod
def serialize(cls, data):
Expand All @@ -87,12 +87,10 @@ def deserialize(cls, file_object):
from ruamel import yaml

try:
data = yaml.round_trip_load(file_object, preserve_quotes=True)
return yaml.round_trip_load(file_object, preserve_quotes=True)
except NotImplementedError as e:
log.error(str(e))
return {}
else:
return data or {}

@classmethod
def serialize(cls, data):
Expand Down Expand Up @@ -131,9 +129,7 @@ def extensions(cls):
def deserialize(cls, file_object):
import yaml

data = yaml.safe_load(file_object) or {}

return data
return yaml.safe_load(file_object)

@classmethod
def serialize(cls, data):
Expand All @@ -160,7 +156,14 @@ def deserialize(path: Path, extension: str, *, formatter=None) -> Dict:
if formatter is None:
formatter = _get_formatter(extension)
with path.open('r') as file_object:
return formatter.deserialize(file_object)
data = formatter.deserialize(file_object)
if data is None:
log.debug(f"No data in {path}")
data = {}
elif not isinstance(data, dict):
log.error(f"Invalid data in {path}: {data!r}")
data = {}
return data


def serialize(data: Dict, extension: str = '.yml', *, formatter=None) -> str:
Expand Down
2 changes: 1 addition & 1 deletion notebooks/file_inference.ipynb
Expand Up @@ -287,7 +287,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/format_options.ipynb
Expand Up @@ -256,7 +256,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/manager_api.ipynb
Expand Up @@ -331,7 +331,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/mapper_api.ipynb
Expand Up @@ -325,7 +325,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/nested_dataclass.ipynb
Expand Up @@ -184,7 +184,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/patched_containers.ipynb
Expand Up @@ -364,7 +364,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
11 changes: 9 additions & 2 deletions notebooks/readme.ipynb
Expand Up @@ -154,7 +154,14 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting inventory/items/widget.yml\n"
"Overwriting inventory/items/widget.yml"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
Expand Down Expand Up @@ -244,7 +251,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/roundtrip_comments.ipynb
Expand Up @@ -239,7 +239,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.8.2"
}
},
"nbformat": 4,
Expand Down
47 changes: 24 additions & 23 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
@@ -1,7 +1,7 @@
[tool.poetry]

name = "datafiles"
version = "0.10b2"
version = "0.10b3"
description = "File-based ORM for dataclasses."

license = "MIT"
Expand Down
13 changes: 13 additions & 0 deletions tests/test_loading.py
Expand Up @@ -79,6 +79,19 @@ def with_extra_fields(sample, expect):

expect(hasattr(sample, 'extra')).is_(False)

def with_invalid_data(sample, expect):
write(
'tmp/sample.yml',
"""
- foo
- bar
""",
)

sample.datafile.load()

expect(sample.int_) == 0


def describe_alternate_formats():
@pytest.fixture
Expand Down

0 comments on commit a0b617c

Please sign in to comment.