from pathlib import Path from website_generator.utils import PathMatcher import typesystem class PathField(typesystem.String): errors = { 'type': 'Must be a string or instance of pathlib.Path.', 'null': 'May not be null.', 'blank': 'Must not be blank.', 'max_length': 'Must have no more than {max_length} characters.', 'min_length': 'Must have at least {min_length} characters.', 'pattern': 'Must match the pattern /{pattern}/.', 'format': 'Must be a valid {format}.', 'not_found': 'Path does not exist.', 'no_files': 'Path must not point to a file.', 'no_dirs': 'Path must not point to a directory.', 'no_symlinks': 'Path must not point to a symbolic link.', } def __init__(self, *, must_exist=True, allow_files=True, allow_folders=False, allow_symlinks=True, **kwargs): super().__init__(**kwargs) self.must_exist = must_exist self.allow_files = must_exist and allow_files self.allow_folders = must_exist and allow_folders self.allow_symlinks = must_exist and allow_symlinks def validate(self, value, *, strict=False): if isinstance(value, Path): value = str(value) value = super().validate(value, strict=strict) if not value: return value value = Path(value) if not self.allow_symlinks and value.is_symlink(): self.validation_error("no_symlinks") value = value.expanduser().resolve() if self.must_exist and not value.exists(): self.validation_error("not_found") if not self.allow_files and value.is_file(): self.validation_error("no_files") if not self.allow_folders and value.is_dir(): self.validation_error("no_dirs") return value class PathMatcherField(typesystem.Union): def __init__(self, *, **kwargs): super().__init__([ typesystem.String(), typesystem.Array( items=typesystem.String(), min_items=1, ), typesystem.Object( properties={ 'include': typesystem.Union([ typesystem.String(), typesystem.Array( items=typesystem.String(), min_items=1, ), ]), 'exclude': typesystem.Union([ typesystem.String(), typesystem.Array( items=typesystem.String(), min_items=1, ), ]), }, min_properties=1, required=['include'], ), ], **kwargs) def validate(self, *args, **kwargs): return PathMatcher(super().validate(*args, **kwargs))