Skip to content

Commit

Permalink
Merge pull request #135 from jacebrowning/formatter-registration
Browse files Browse the repository at this point in the history
Add registration system for custom formatter classes
  • Loading branch information
jacebrowning committed Nov 10, 2019
2 parents c3fa58e + c3b50e2 commit bd377ed
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 106 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.6 (unreleased)

- Added a registration system for custom formatter classes.

# 0.5 (2019-09-28)

- Added an `INDENT_YAML_BLOCKS` setting to optionally use the old serialization behavior.
Expand Down Expand Up @@ -28,9 +32,9 @@

- Added an option to automatically resave files after loading.
- Added an option to automatically reload files after saving.
- Added registration system for custom class converters.
- Added a registration system for custom converter classes.
- Added initial support for file inference via `auto(filename)`.

# 0.1 (2019-01-13)

- Initial release.
- Initial release.
1 change: 1 addition & 0 deletions datafiles/converters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@


def register(cls: Union[type, str], converter: type):
"""Associate the given type signature with a converter class."""
_REGISTRY[cls] = converter
if not isinstance(cls, str):
_REGISTRY[cls.__name__] = converter
Expand Down
28 changes: 21 additions & 7 deletions datafiles/formats.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
from abc import ABCMeta, abstractmethod
from contextlib import suppress
from io import StringIO
from pathlib import Path
from typing import IO, Any, Dict, List
Expand All @@ -11,6 +12,14 @@
from . import settings


_REGISTRY: Dict[str, type] = {}


def register(extension: str, formatter: type):
"""Associate the given file extension with a formatter class."""
_REGISTRY[extension] = formatter


class Formatter(metaclass=ABCMeta):
"""Base class for object serialization and text deserialization."""

Expand Down Expand Up @@ -92,17 +101,22 @@ def serialize(cls, data):


def deserialize(path: Path, extension: str) -> Dict:
for formatter in Formatter.__subclasses__():
if extension in formatter.extensions():
with path.open('r') as file_object:
return formatter.deserialize(file_object)

raise ValueError(f'Unsupported file extension: {extension}')
formatter = _get_formatter(extension)
with path.open('r') as file_object:
return formatter.deserialize(file_object)


def serialize(data: Dict, extension: str = '.yml') -> str:
formatter = _get_formatter(extension)
return formatter.serialize(data)


def _get_formatter(extension: str):
with suppress(KeyError):
return _REGISTRY[extension]

for formatter in Formatter.__subclasses__():
if extension in formatter.extensions():
return formatter.serialize(data)
return formatter

raise ValueError(f'Unsupported file extension: {extension!r}')
31 changes: 26 additions & 5 deletions docs/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ The following formats are supported for serialization.

## YAML

By default, datafiles uses the [YAML language](https://yaml.org/) for serialization. Any of the following file extensions will use this format:
By default, datafiles uses the [YAML language](https://yaml.org/) for serialization.
Any of the following file extensions will use this format:

- `.yml`
- `.yaml`
Expand All @@ -16,8 +17,8 @@ Sample output:
my_dict:
value: 0
my_list:
- value: 1
- value: 2
- value: 1
- value: 2
my_bool: true
my_float: 1.23
my_int: 42
Expand All @@ -28,7 +29,8 @@ Where possible, comments and whitespace are preserved in files as shown in this

## JSON

The [JSON language](https://www.json.org/) is also supported. Any of the following file extensions will use this format:
The [JSON language](https://www.json.org/) is also supported.
Any of the following file extensions will use this format:

- `.json`

Expand Down Expand Up @@ -58,7 +60,8 @@ Additional examples can be found in this [Jupyter Notebook](https://github.com/j

## TOML

The [TOML language](https://github.com/toml-lang/toml) is also supported. Any of the following file extensions will use this format:
The [TOML language](https://github.com/toml-lang/toml) is also supported.
Any of the following file extensions will use this format:

- `.toml`

Expand All @@ -81,3 +84,21 @@ value = 0
```

Additional examples can be found in this [Jupyter Notebook](https://github.com/jacebrowning/datafiles/blob/develop/notebooks/format_options.ipynb).

## Custom Formats

Additional formats are supported through a registration system.
Either extend the `datafiles.formats.Formatter` base class or map one of the existing formatter classes:

```
#!python hl_lines="4"
from datafile import datafile, formats
formats.register('.conf', formats.YAML)
@datafile("my-file-path.conf")
class MyConfig:
...
```
Loading

0 comments on commit bd377ed

Please sign in to comment.