diff --git a/CHANGELOG.md b/CHANGELOG.md index df36685681efec06e9f6cc6a51dc4e7bf2a0eb05..25e15965c8eee3ca529baf4c9c7b57586f4aa4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ # v2.16 * changed semantics of `wrap_future` +* added `Directory` to schema configuration diff --git a/docs/configuration/schema.rst b/docs/configuration/schema.rst index ae14194c98a71ddec85bc4c5c69037c851c2406b..ef83f2989da4df24c4a22e99c1bd35d60393f401 100644 --- a/docs/configuration/schema.rst +++ b/docs/configuration/schema.rst @@ -17,6 +17,14 @@ you should instantiate a Descriptor. Descriptor reflects how your config is nest .. autoclass:: satella.configuration.schema.File +.. autoclass:: satella.configuration.schema.FileObject + :members: + +.. autoclass:: satella.configuration.schema.Directory + +.. autoclass:: satella.configuration.schema.DirectoryObject + :members: + .. autoclass:: satella.configuration.schema.basic.FileObject .. autoclass:: satella.configuration.schema.IPv4 @@ -71,15 +79,17 @@ Note that providing a short-hand, string type is impossible for descriptors that Available string types are: -* **int** - Integer -* **str** - String -* **list** - List -* **dict** - Dict -* **ipv4** - IPv4 -* **any** - Descriptor -* **bool** - Boolean -* **union** - Union -* **caster** - Caster +* **int** - :class:`~satella.configuration.schema.Integer` +* **str** - :class:`~satella.configuration.schema.String` +* **list** - :class:`~satella.configuration.schema.List` +* **dict** - :class:`~satella.configuration.schema.Dict` +* **ipv4** - :class:`~satella.configuration.schema.IPv4` +* **any** - :class:`~satella.configuration.schema.Descriptor` +* **bool** - :class:`~satella.configuration.schema.Boolean` +* **union** - :class:`~satella.configuration.schema.Union` +* **caster** - :class:`~satella.configuration.schema.Caster` +* **file** - :class:`~satella.configuration.schema.File` +* **dir** - :class:`~satella.configuration.schema.Directory` Lists you define as following diff --git a/satella/__init__.py b/satella/__init__.py index e74eabb222b8ba857449b73eeabc233d9b58c3ae..50a1c84bbf85ed4f580fa779ee011d811959e361 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.16a1' +__version__ = '2.16' diff --git a/satella/configuration/schema/__init__.py b/satella/configuration/schema/__init__.py index a1f61b57ae317b532db63507b3d6eb36870c368f..e13557041874bcf75d8f42937edb54ca63873e93 100644 --- a/satella/configuration/schema/__init__.py +++ b/satella/configuration/schema/__init__.py @@ -1,9 +1,10 @@ from .base import CheckerCondition, Descriptor -from .basic import IPv4, Integer, String, Float, Boolean +from .basic import IPv4, Integer, String, Float, Boolean, File, Directory, FileObject, DirectoryObject from .from_json import descriptor_from_dict from .registry import register_custom_descriptor from .structs import Union, List, Dict, Caster, create_key __all__ = ['CheckerCondition', 'Descriptor', 'descriptor_from_dict', 'IPv4', 'Integer', 'String', 'Float', 'Boolean', 'Union', 'List', 'Dict', 'Caster', + 'File', 'FileObject', 'DirectoryObject', 'Directory', 'register_custom_descriptor', 'create_key'] diff --git a/satella/configuration/schema/basic.py b/satella/configuration/schema/basic.py index 5c16bd26fd230805440b74050c054c06743c0760..4eff8c35204699adcd7e312be760819e580b579d 100644 --- a/satella/configuration/schema/basic.py +++ b/satella/configuration/schema/basic.py @@ -71,7 +71,7 @@ class FileObject: return self.path def __eq__(self, other) -> bool: - return self.path == str(other) + return self.path == str(other) and isinstance(other, FileObject) def __hash__(self) -> int: return hash(self.path) @@ -95,6 +95,37 @@ class FileObject: return open(self.path, mode) +class DirectoryObject: + """ + What you get for values in schema of :class:`~satella.configuration.schema.Directory`. + + This object is comparable and hashable, and is equal to the string of it's path + """ + __slots__ = 'path', + + def __init__(self, path: str): + self.path = path + + def __repr__(self): + return '<Directory object %s>' % (self.path, ) + + def __str__(self): + return self.path + + def __eq__(self, other) -> bool: + return self.path == str(other) and isinstance(other, DirectoryObject) + + def __hash__(self) -> int: + return hash(self.path) + + def get_files(self) -> tp.Iterable[str]: + """ + Return a list of files inside this directory + :return: + """ + return os.listdir(self.path) + + @staticmethod def _make_file(v: str) -> bool: @@ -114,6 +145,25 @@ class File(Descriptor): BASIC_MAKER = _make_file +@staticmethod +def _make_directory(v: str) -> bool: + + if not os.path.isdir(v): + raise ConfigurationValidationError('Expected to find a directory under %s' + % (v,)) + return DirectoryObject(v) + + +@register_custom_descriptor('dir') +class Directory(Descriptor): + """ + This value must be a valid path to a file. The value in your schema will be + an instance of :class:`~satella.configuration.schema.basic.FileObject` + """ + + BASIC_MAKER = _make_directory + + class Regexp(String): """ Base class for declaring regexp-based descriptors. Overload it's attribute REGEXP. Use as