Решение на In-memory файлова система от Ивайло Караманолев

Обратно към всички решения

Към профила на Ивайло Караманолев

Резултати

  • 10 точки от тестове
  • 0 бонус точки
  • 10 точки общо
  • 15 успешни тест(а)
  • 3 неуспешни тест(а)

Код

class FileSystemError(Exception):
pass
class FileSystemMountError(Exception):
pass
class NotAMountpointError(FileSystemMountError):
pass
class MountPointDoesNotExistError(FileSystemMountError):
pass
class MountPointNotEmptyError(FileSystemMountError):
pass
class MountPointNotADirectoryError(FileSystemMountError):
pass
class NonExplicitDirectoryDeletionError(FileSystemError):
pass
class LinkPathError(FileSystemError):
pass
class NonEmptyDirectoryDeletionError(FileSystemError):
pass
class DirectoryHardLinkError(FileSystemError):
pass
class NotEnoughSpaceError(FileSystemError):
pass
class DestinationNotADirectoryError(FileSystemError):
pass
class InvalidPathError(FileSystemError):
pass
class NodeDoesNotExistError(FileSystemError):
pass
class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
pass
class SourceNodeDoesNotExistError(NodeDoesNotExistError):
pass
class DestinationNodeExistsError(FileSystemError):
pass
class DirectoryNode(object):
def __init__(self):
self._nodes = {}
@property
def _size(self):
return 1
@property
def size(self):
return self._size + sum(n.size for n in self._nodes.values())
@property
def is_directory(self):
return True
@property
def nodes(self):
return list(self._nodes.values())
@property
def files(self):
return [n for n in self._nodes.values() if n.is_directory is False]
@property
def directories(self):
return [n for n in self._nodes.values() if n.is_directory is True]
@property
def nodes_dict(self):
return self._nodes
class MountPointNode(object):
def __init__(self, filesystem):
self.filesystem = filesystem
@property
def is_directory(self):
return True
@property
def _size(self):
return 1
@property
def nodes(self):
return self.filesystem.root.nodes
@property
def files(self):
return self.filesystem.root.files
@property
def directories(self):
return self.filesystem.root.directories
@property
def nodes_dict(self):
return self.filesystem.root.nodes_dict
class ContentNode(object):
def __init__(self, content):
self.content = content
@property
def size(self):
return len(self.content)
@property
def _size(self):
return self.size
class FileNode(object):
def __init__(self, content_node):
self.content_node = content_node
@property
def content(self):
return self.content_node.content
@property
def size(self):
return self.content_node.size + 1
@property
def _size(self):
return 1
def truncate(self, content):
self.content_node.content = content
def append(self, content):
self.content_node.content += content
@property
def is_directory(self):
return False
class SymbolicLinkNode(object):
def __init__(self, filesystem, path):
self.filesystem = filesystem
self.path = path
@property
def _size(self):
return 1
@property
def node(self):
try:
return self.filesystem.get_node(self.path)
except NodeDoesNotExistError:
raise LinkPathError()
@property
def is_directory(self):
return self.node.is_directory
@property
def nodes(self):
if not self.node.is_directory:
raise AttributeError()
return self.node.nodes
@property
def files(self):
if not self.node.is_directory:
raise AttributeError()
return self.node.files
@property
def directories(self):
if not self.node.is_directory:
raise AttributeError()
return self.node.directories
@property
def nodes_dict(self):
if not self.node.is_directory:
raise AttributeError()
return self.node.nodes_dict
@property
def content(self):
if self.node.is_directory:
raise AttributeError()
return self.node.content
def truncate(self, content):
if self.node.is_directory:
raise AttributeError()
self.node.truncate(content)
def append(self, content):
if self.node.is_directory:
raise AttributeError()
self.node.append(content)
class FileSystem(object):
def __init__(self, size):
if size < 1:
raise NotEnoughSpaceError()
self.root = DirectoryNode()
self.size = size
def __get_node(self, path):
node = self.root
for part in path:
if not node.is_directory:
raise NodeDoesNotExistError()
node = node.nodes_dict.get(part)
if node is None:
raise NodeDoesNotExistError()
return node
def _get_node(self, path):
node = self.__get_node(path)
if type(node) is MountPointNode:
return node.filesystem.root
return node
def _get_fs(self, path):
node = self.root
fs = self
for part in path:
if not node.is_directory:
raise NodeDoesNotExistError()
node = node._nodes.get(part)
if type(node) is MountPointNode:
fs = node.filesystem
if node is None:
raise NodeDoesNotExistError()
return fs
def validate_path(self, path):
if path == '':
raise NodeDoesNotExistError()
if path == '/':
return []
parts = path.split('/')
if len(parts) < 2 or parts[0] or not all(parts[1:]):
raise InvalidPathError()
return parts[1:]
def get_node(self, path):
return self._get_node(self.validate_path(path))
def create(self, path, directory=False, content=''):
parts = self.validate_path(path)
if len(parts) == 0:
raise DestinationNodeExistsError()
try:
node = self._get_node(parts[:-1])
node_fs = self._get_fs(parts[:-1])
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError()
if directory:
required_space = 1
new_node = DirectoryNode()
else:
required_space = 1 + len(content)
new_node = FileNode(ContentNode(content))
if parts[-1] in node.nodes_dict:
raise DestinationNodeExistsError()
if node_fs.available_size < required_space:
raise NotEnoughSpaceError()
node.nodes_dict[parts[-1]] = new_node
def remove(self, path, directory=False, force=False):
parts = self.validate_path(path)
if len(parts) == 0:
raise FileSystemError()
try:
node = self._get_node(parts[:-1])
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError()
dest_node = node.nodes_dict.get(parts[-1])
if dest_node is None:
raise DestinationNodeDoesNotExistError()
if dest_node.is_directory:
if not directory:
raise NonExplicitDirectoryDeletionError()
if len(dest_node.nodes_dict) != 0 and not force:
raise NonEmptyDirectoryDeletionError()
del node.nodes_dict[parts[-1]]
def move(self, source, destination):
src_parts = self.validate_path(source)
dst_parts = self.validate_path(destination)
try:
src_dir = self._get_node(src_parts[:-1])
except NodeDoesNotExistError:
raise SourceNodeDoesNotExistError()
if src_parts[-1] not in src_dir.nodes_dict:
raise SourceNodeDoesNotExistError()
try:
dst_dir = self._get_node(dst_parts)
dst_dir_fs = self._get_fs(dst_parts)
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError()
if not dst_dir.is_directory:
raise DestinationNotADirectoryError()
if src_parts[-1] in dst_dir.nodes_dict:
raise DestinationNodeExistsError()
dst_dir.nodes_dict[src_parts[-1]] = src_dir.nodes_dict[src_parts[-1]]
del src_dir.nodes_dict[src_parts[-1]]
if dst_dir_fs.available_size < 0:
src_dir.nodes_dict[src_parts[-1]] = \
dst_dir.nodes_dict[src_parts[-1]]
del dst_dir.nodes_dict[src_parts[-1]]
def link(self, source, destination, symbolic=True):
src_parts = self.validate_path(source)
dst_parts = self.validate_path(destination)
try:
src_node = self._get_node(src_parts)
except NodeDoesNotExistError:
if symbolic:
raise NodeDoesNotExistError()
else:
raise SourceNodeDoesNotExistError()
if not symbolic and src_node.is_directory:
raise DirectoryHardLinkError()
try:
dst_dir = self._get_node(dst_parts[:-1])
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError()
if dst_parts[-1] in dst_dir.nodes_dict:
raise DestinationNodeExistsError()
if not symbolic:
dst_dir.nodes_dict[dst_parts[-1]] = FileNode(src_node.content_node)
else:
dst_dir.nodes_dict[dst_parts[-1]] = SymbolicLinkNode(self, source)
def mount(self, file_system, path):
parts = self.validate_path(path)
try:
node = self._get_node(parts)
node_dir = self._get_node(parts[:-1])
except NodeDoesNotExistError:
raise MountPointDoesNotExistError()
if node.is_directory is False:
raise MountPointNotADirectoryError()
if len(node.nodes) != 0:
raise MountPointNotEmptyError()
node_dir.nodes_dict[parts[-1]] = MountPointNode(file_system)
def unmount(self, path):
parts = self.validate_path(path)
node = self.__get_node(parts)
node_dir = self._get_node(parts[:-1])
if type(node) is not MountPointNode:
raise NotAMountpointError()
node_dir.nodes_dict[parts[-1]] = DirectoryNode()
@property
def available_size(self):
nodes = set()
def walk(node):
nodes.add(node)
if type(node) is FileNode:
nodes.add(node.content_node)
if type(node) is DirectoryNode:
for child in node.nodes:
walk(child)
walk(self.root)
return self.size - sum(n._size for n in nodes)

Лог от изпълнението

........E....E..E.
======================================================================
ERROR: test_mounting (test.TestFileSystem)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "lib/language/python/runner.py", line 65, in thread
    raise TimeoutError
TimeoutError

======================================================================
ERROR: test_remove_empty_directory (test.TestFileSystem)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "lib/language/python/runner.py", line 65, in thread
    raise TimeoutError
TimeoutError

======================================================================
ERROR: test_symlink_to_missing_file (test.TestFileSystem)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "lib/language/python/runner.py", line 65, in thread
    raise TimeoutError
TimeoutError

----------------------------------------------------------------------
Ran 18 tests in 6.178s

FAILED (errors=3)

История (1 версия и 0 коментара)

Ивайло обнови решението на 30.04.2015 16:27 (преди почти 9 години)

+class FileSystemError(Exception):
+ pass
+
+
+class FileSystemMountError(Exception):
+ pass
+
+
+class NotAMountpointError(FileSystemMountError):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class InvalidPathError(FileSystemError):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class DirectoryNode(object):
+ def __init__(self):
+ self._nodes = {}
+
+ @property
+ def _size(self):
+ return 1
+
+ @property
+ def size(self):
+ return self._size + sum(n.size for n in self._nodes.values())
+
+ @property
+ def is_directory(self):
+ return True
+
+ @property
+ def nodes(self):
+ return list(self._nodes.values())
+
+ @property
+ def files(self):
+ return [n for n in self._nodes.values() if n.is_directory is False]
+
+ @property
+ def directories(self):
+ return [n for n in self._nodes.values() if n.is_directory is True]
+
+ @property
+ def nodes_dict(self):
+ return self._nodes
+
+
+class MountPointNode(object):
+ def __init__(self, filesystem):
+ self.filesystem = filesystem
+
+ @property
+ def is_directory(self):
+ return True
+
+ @property
+ def _size(self):
+ return 1
+
+ @property
+ def nodes(self):
+ return self.filesystem.root.nodes
+
+ @property
+ def files(self):
+ return self.filesystem.root.files
+
+ @property
+ def directories(self):
+ return self.filesystem.root.directories
+
+ @property
+ def nodes_dict(self):
+ return self.filesystem.root.nodes_dict
+
+
+class ContentNode(object):
+ def __init__(self, content):
+ self.content = content
+
+ @property
+ def size(self):
+ return len(self.content)
+
+ @property
+ def _size(self):
+ return self.size
+
+
+class FileNode(object):
+ def __init__(self, content_node):
+ self.content_node = content_node
+
+ @property
+ def content(self):
+ return self.content_node.content
+
+ @property
+ def size(self):
+ return self.content_node.size + 1
+
+ @property
+ def _size(self):
+ return 1
+
+ def truncate(self, content):
+ self.content_node.content = content
+
+ def append(self, content):
+ self.content_node.content += content
+
+ @property
+ def is_directory(self):
+ return False
+
+
+class SymbolicLinkNode(object):
+ def __init__(self, filesystem, path):
+ self.filesystem = filesystem
+ self.path = path
+
+ @property
+ def _size(self):
+ return 1
+
+ @property
+ def node(self):
+ try:
+ return self.filesystem.get_node(self.path)
+ except NodeDoesNotExistError:
+ raise LinkPathError()
+
+ @property
+ def is_directory(self):
+ return self.node.is_directory
+
+ @property
+ def nodes(self):
+ if not self.node.is_directory:
+ raise AttributeError()
+ return self.node.nodes
+
+ @property
+ def files(self):
+ if not self.node.is_directory:
+ raise AttributeError()
+ return self.node.files
+
+ @property
+ def directories(self):
+ if not self.node.is_directory:
+ raise AttributeError()
+ return self.node.directories
+
+ @property
+ def nodes_dict(self):
+ if not self.node.is_directory:
+ raise AttributeError()
+ return self.node.nodes_dict
+
+ @property
+ def content(self):
+ if self.node.is_directory:
+ raise AttributeError()
+ return self.node.content
+
+ def truncate(self, content):
+ if self.node.is_directory:
+ raise AttributeError()
+ self.node.truncate(content)
+
+ def append(self, content):
+ if self.node.is_directory:
+ raise AttributeError()
+ self.node.append(content)
+
+
+class FileSystem(object):
+ def __init__(self, size):
+ if size < 1:
+ raise NotEnoughSpaceError()
+ self.root = DirectoryNode()
+ self.size = size
+
+ def __get_node(self, path):
+ node = self.root
+ for part in path:
+ if not node.is_directory:
+ raise NodeDoesNotExistError()
+ node = node.nodes_dict.get(part)
+ if node is None:
+ raise NodeDoesNotExistError()
+ return node
+
+ def _get_node(self, path):
+ node = self.__get_node(path)
+ if type(node) is MountPointNode:
+ return node.filesystem.root
+ return node
+
+ def _get_fs(self, path):
+ node = self.root
+ fs = self
+ for part in path:
+ if not node.is_directory:
+ raise NodeDoesNotExistError()
+ node = node._nodes.get(part)
+ if type(node) is MountPointNode:
+ fs = node.filesystem
+ if node is None:
+ raise NodeDoesNotExistError()
+ return fs
+
+ def validate_path(self, path):
+ if path == '':
+ raise NodeDoesNotExistError()
+ if path == '/':
+ return []
+ parts = path.split('/')
+ if len(parts) < 2 or parts[0] or not all(parts[1:]):
+ raise InvalidPathError()
+ return parts[1:]
+
+ def get_node(self, path):
+ return self._get_node(self.validate_path(path))
+
+ def create(self, path, directory=False, content=''):
+ parts = self.validate_path(path)
+ if len(parts) == 0:
+ raise DestinationNodeExistsError()
+ try:
+ node = self._get_node(parts[:-1])
+ node_fs = self._get_fs(parts[:-1])
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+ if directory:
+ required_space = 1
+ new_node = DirectoryNode()
+ else:
+ required_space = 1 + len(content)
+ new_node = FileNode(ContentNode(content))
+ if parts[-1] in node.nodes_dict:
+ raise DestinationNodeExistsError()
+ if node_fs.available_size < required_space:
+ raise NotEnoughSpaceError()
+ node.nodes_dict[parts[-1]] = new_node
+
+ def remove(self, path, directory=False, force=False):
+ parts = self.validate_path(path)
+ if len(parts) == 0:
+ raise FileSystemError()
+ try:
+ node = self._get_node(parts[:-1])
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+ dest_node = node.nodes_dict.get(parts[-1])
+ if dest_node is None:
+ raise DestinationNodeDoesNotExistError()
+ if dest_node.is_directory:
+ if not directory:
+ raise NonExplicitDirectoryDeletionError()
+ if len(dest_node.nodes_dict) != 0 and not force:
+ raise NonEmptyDirectoryDeletionError()
+ del node.nodes_dict[parts[-1]]
+
+ def move(self, source, destination):
+ src_parts = self.validate_path(source)
+ dst_parts = self.validate_path(destination)
+ try:
+ src_dir = self._get_node(src_parts[:-1])
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError()
+ if src_parts[-1] not in src_dir.nodes_dict:
+ raise SourceNodeDoesNotExistError()
+ try:
+ dst_dir = self._get_node(dst_parts)
+ dst_dir_fs = self._get_fs(dst_parts)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+ if not dst_dir.is_directory:
+ raise DestinationNotADirectoryError()
+ if src_parts[-1] in dst_dir.nodes_dict:
+ raise DestinationNodeExistsError()
+ dst_dir.nodes_dict[src_parts[-1]] = src_dir.nodes_dict[src_parts[-1]]
+ del src_dir.nodes_dict[src_parts[-1]]
+ if dst_dir_fs.available_size < 0:
+ src_dir.nodes_dict[src_parts[-1]] = \
+ dst_dir.nodes_dict[src_parts[-1]]
+ del dst_dir.nodes_dict[src_parts[-1]]
+
+ def link(self, source, destination, symbolic=True):
+ src_parts = self.validate_path(source)
+ dst_parts = self.validate_path(destination)
+ try:
+ src_node = self._get_node(src_parts)
+ except NodeDoesNotExistError:
+ if symbolic:
+ raise NodeDoesNotExistError()
+ else:
+ raise SourceNodeDoesNotExistError()
+ if not symbolic and src_node.is_directory:
+ raise DirectoryHardLinkError()
+ try:
+ dst_dir = self._get_node(dst_parts[:-1])
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+ if dst_parts[-1] in dst_dir.nodes_dict:
+ raise DestinationNodeExistsError()
+ if not symbolic:
+ dst_dir.nodes_dict[dst_parts[-1]] = FileNode(src_node.content_node)
+ else:
+ dst_dir.nodes_dict[dst_parts[-1]] = SymbolicLinkNode(self, source)
+
+ def mount(self, file_system, path):
+ parts = self.validate_path(path)
+ try:
+ node = self._get_node(parts)
+ node_dir = self._get_node(parts[:-1])
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError()
+ if node.is_directory is False:
+ raise MountPointNotADirectoryError()
+ if len(node.nodes) != 0:
+ raise MountPointNotEmptyError()
+ node_dir.nodes_dict[parts[-1]] = MountPointNode(file_system)
+
+ def unmount(self, path):
+ parts = self.validate_path(path)
+ node = self.__get_node(parts)
+ node_dir = self._get_node(parts[:-1])
+ if type(node) is not MountPointNode:
+ raise NotAMountpointError()
+ node_dir.nodes_dict[parts[-1]] = DirectoryNode()
+
+ @property
+ def available_size(self):
+ nodes = set()
+
+ def walk(node):
+ nodes.add(node)
+ if type(node) is FileNode:
+ nodes.add(node.content_node)
+ if type(node) is DirectoryNode:
+ for child in node.nodes:
+ walk(child)
+
+ walk(self.root)
+ return self.size - sum(n._size for n in nodes)