Skip to content

Commit

Permalink
Merge pull request #239 from jacebrowning/union-types
Browse files Browse the repository at this point in the history
Support optionals via union types
  • Loading branch information
jacebrowning committed Nov 2, 2021
2 parents 46aafe2 + db1cfb5 commit 07704c5
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 23 deletions.
1 change: 1 addition & 0 deletions .pylint.ini
Expand Up @@ -36,6 +36,7 @@ disable=
cell-var-from-loop,
cyclic-import,
comparison-with-callable,
unsupported-binary-operation,

init-import=yes

Expand Down
5 changes: 3 additions & 2 deletions .travis.yml
Expand Up @@ -22,8 +22,9 @@ install:
script:
- make test-repeat
- make check
- make notebooks
- make mkdocs
# TODO: Get targets working with Python 3.10
# - make notebooks
# - make mkdocs

after_success:
- pip install coveralls
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,7 @@
# 1.1 (beta)

- Added support for Python 3.10's builtin optional types (e.g. `int | None`).

# 1.0 (2021-10-04)

- Initial stable release.
Expand Down
9 changes: 9 additions & 0 deletions datafiles/converters/__init__.py
@@ -1,5 +1,6 @@
import dataclasses
import inspect
import types
from enum import Enum
from inspect import isclass
from typing import Any, Dict, Mapping, Optional, Union
Expand Down Expand Up @@ -65,6 +66,14 @@ def map_type(cls, *, name: str = '', item_cls: Optional[type] = None):
log.debug(f'Mapped {cls!r} to new converter: {converter}')
return converter

if hasattr(types, 'UnionType') and isinstance(cls, types.UnionType): # type: ignore
# Python 3.10 behavior
converter = map_type(cls.__args__[0])
assert len(cls.__args__) == 2
assert cls.__args__[1] == type(None)
converter = converter.as_optional()
return converter

cls = resolve(cls)

if hasattr(cls, '__origin__'):
Expand Down
10 changes: 10 additions & 0 deletions datafiles/tests/__init__.py
@@ -1 +1,11 @@
"""Unit tests for the package."""

import sys

import pytest


xfail_without_pep_604 = pytest.mark.xfail(
sys.version_info < (3, 10),
reason="Union types (PEP 604) are not available in Python 3.9 and earlier",
)
9 changes: 9 additions & 0 deletions datafiles/tests/test_converters.py
Expand Up @@ -9,6 +9,8 @@

from datafiles import converters, settings

from . import xfail_without_pep_604


@dataclass
class MyDataclass:
Expand Down Expand Up @@ -102,7 +104,14 @@ def it_handles_enums(expect):
converter = converters.map_type(Color)
expect(converter.__name__) == 'ColorConverter'

@xfail_without_pep_604
def it_handles_optionals(expect):
converter = converters.map_type(str | None) # type: ignore
expect(converter.__name__) == 'OptionalString'
expect(converter.TYPE) == str
expect(converter.DEFAULT).is_(None)

def it_handles_optionals_with_legacy_syntax(expect):
converter = converters.map_type(Optional[str])
expect(converter.__name__) == 'OptionalString'
expect(converter.TYPE) == str
Expand Down
45 changes: 28 additions & 17 deletions poetry.lock

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

7 changes: 3 additions & 4 deletions pyproject.toml
@@ -1,7 +1,7 @@
[tool.poetry]

name = "datafiles"
version = "1.0"
version = "1.1b1"
description = "File-based ORM for dataclasses."

license = "MIT"
Expand Down Expand Up @@ -65,8 +65,7 @@ black = "=21.9b0"
isort = "=5.9.2"

# Linters
mypy = "~0.790"
typed_ast = "^1.4.3" # updated mypy dependency for Python 3.10
mypy = "~0.910"
pylint = "~2.7.4"
pydocstyle = "*"

Expand All @@ -85,7 +84,7 @@ pytest-profiling = "*"
coveragespace = "^4.0"

# Documentation
mkdocs = "~1.0"
mkdocs = "~1.0.4"
pygments = "^2.9"

# Notebooks
Expand Down

0 comments on commit 07704c5

Please sign in to comment.