From 06008146fe5e99c3bc3fa252650c9513ecfbf016 Mon Sep 17 00:00:00 2001 From: Josep Cugat Date: Tue, 6 Feb 2018 14:56:45 +0100 Subject: [PATCH] Subclass abcmeta (#123) * Added compatibility with python's ABC * Added documentation * Added link --- HISTORY.rst | 4 ++++ docs/examples/ex_abc.py | 11 +++++++++++ docs/index.rst | 8 ++++++++ pydantic/main.py | 3 ++- tests/test_abc.py | 44 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 docs/examples/ex_abc.py create mode 100644 tests/test_abc.py diff --git a/HISTORY.rst b/HISTORY.rst index 13ac9c6..3cfa960 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,10 @@ History ------- +v0.6.5 (2018-02-XX) +................... +* added compatibility with abstract base classes (ABCs) #123 + v0.6.4 (2018-02-01) ................... * allow python date and times objects #122 diff --git a/docs/examples/ex_abc.py b/docs/examples/ex_abc.py new file mode 100644 index 0000000..f325199 --- /dev/null +++ b/docs/examples/ex_abc.py @@ -0,0 +1,11 @@ +import abc +from pydantic import BaseModel + + +class FooBarModel(BaseModel, abc.ABC): + a: str + b: int + + @abc.abstractmethod + def my_abstract_method(self): + pass diff --git a/docs/index.rst b/docs/index.rst index f1bce3c..9536bc2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -335,6 +335,14 @@ Using the same plumbing as ``copy()`` pydantic models support efficient pickling .. literalinclude:: examples/ex_pickle.py +Abstract Base Classes +..................... + +Pydantic models can be used alongside Python's +`Abstract Base Classes `_ (ABCs). + +.. literalinclude:: examples/ex_abc.py + .. _benchmarks_tag: Benchmarks diff --git a/pydantic/main.py b/pydantic/main.py index f5ea6a0..abffb96 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -1,4 +1,5 @@ import warnings +from abc import ABCMeta from collections import OrderedDict from pathlib import Path from types import FunctionType @@ -51,7 +52,7 @@ def _extract_validators(namespace): return validators -class MetaModel(type): +class MetaModel(ABCMeta): @classmethod def __prepare__(mcs, *args, **kwargs): return OrderedDict() diff --git a/tests/test_abc.py b/tests/test_abc.py new file mode 100644 index 0000000..f1ec3d3 --- /dev/null +++ b/tests/test_abc.py @@ -0,0 +1,44 @@ +import abc + +import pytest + +from pydantic import BaseModel + + +def test_model_subclassing_abstract_base_classes(): + class Model(BaseModel, abc.ABC): + some_field: str + + +def test_model_subclassing_abstract_base_classes_without_implementation_raises_exception(): + class Model(BaseModel, abc.ABC): + some_field: str + + @abc.abstractmethod + def my_abstract_method(self): + pass + + @classmethod + @abc.abstractmethod + def my_abstract_classmethod(cls): + pass + + @staticmethod + @abc.abstractmethod + def my_abstract_staticmethod(): + pass + + @property + @abc.abstractmethod + def my_abstract_property(self): + pass + + @my_abstract_property.setter + @abc.abstractmethod + def my_abstract_property(self, val): + pass + + with pytest.raises(TypeError) as excinfo: + Model(some_field='some_value') + assert str(excinfo.value) == "Can't instantiate abstract class Model with abstract methods" \ + " my_abstract_classmethod, my_abstract_method, my_abstract_property, my_abstract_staticmethod"