Решение на In-memory файлова система от Димитър Влаховски

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

Към профила на Димитър Влаховски

Резултати

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

Код

class Dir:
def __init__(self, name):
self.name = name
self._nodes = {}
self.is_directory = True
def __contains__(self, node):
return node in self._nodes.values()
def is_filesystem(self):
return False
@property
def directories(self):
nodes = list(filter(lambda x: not x.is_filesystem(),
self._nodes.values()))
return [node for node in nodes if node.is_directory]
@property
def files(self):
nodes = list(filter(lambda x: not x.is_filesystem(),
self._nodes.values()))
return [node for node in nodes
if not node.is_directory]
@property
def nodes(self):
return list(self._nodes.values())
@property
def size(self):
return (1 + sum([node.size for node in self.directories]) +
sum([node.real_size for node in self.files]))
def contains_path(self, path):
return path in self._nodes
class File():
def __init__(self, name, content, fs):
self.name = name
self.encoding = "utf-8"
self._content = bytearray(content, self.encoding)
self.hard_links_count = 1
self.is_directory = False
self.fs = fs
@property
def size(self):
return len(self._content) + 1
@property
def real_size(self):
return len(self._content)/self.hard_links_count + 1
@property
def content(self):
return self._content.decode(self.encoding)
def is_filesystem(self):
return False
def append(self, text):
if self.fs.available_size + len(text) > self.fs.size:
raise NotEnoughSpaceError()
self._content.extend(bytearray(text, self.encoding))
def truncate(self, text):
if self.fs.available_size - self.size + len(text) + 1 > self.fs.size:
raise NotEnoughSpaceError()
self._content.clear()
self._content.extend(bytearray(text, self.encoding))
class Symlink:
def __init__(self, link, fs):
self.link_path = link
self.size = 1
self.fs = fs
self.is_directory = fs.get_node(link).is_directory
def is_filesystem(self):
return False
@property
def real_size(self):
return self.size
def __getattr__(self, name):
try:
node = self.fs.get_node(self.link_path)
except NodeDoesNotExistError:
raise LinkPathError
return getattr(node, name)
class FileSystem:
def __init__(self, size, dir_separator='/'):
if size <= 0:
raise NotEnoughSpaceError()
self.size = size
self.dir_separator = dir_separator
self.root = Dir(self.dir_separator)
@property
def available_size(self):
return int(self.size - self.root.size)
def is_filesystem(self):
return True
def split_path(self, path):
return [segment for segment in path.split(self.dir_separator)
if segment != '']
def get_basepath_and_path(self, path_):
split_path = self.split_path(path_)
path = split_path[-1]
base_path = self.dir_separator.join(split_path[:-1])
if len(base_path.strip()) == 0:
base_path = self.dir_separator
return (base_path, path)
def get_node(self, path):
if len(path.strip()) == 0:
raise NodeDoesNotExistError
if len(path.strip().replace(self.dir_separator, "")) == 0:
return self.root
current = self.root
segments = self.split_path(path)
for segment in segments:
if current.contains_path(segment):
current = current._nodes[segment]
if current.is_filesystem():
current = current.root
else:
raise NodeDoesNotExistError('"{}" does not exist'.format(path))
return current
def create(self, path, directory=False, content=''):
node = None
parent, name = self.get_basepath_and_path(path)
node = Dir(name) if directory else File(name, content, self)
if self.available_size - node.size < 0:
raise NotEnoughSpaceError()
try:
destination = self.get_node(parent)
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError()
if destination.contains_path(name):
raise DestinationNodeExistsError()
destination._nodes[name] = node
def remove(self, path, directory=False, force=True):
node = self.get_node(path)
if node.is_directory and not directory:
raise NonExplicitDirectoryDeletionError()
if node.is_directory and not force and len(node.nodes) != 0:
raise NonEmptyDirectoryDeletionError()
parent, name = self.get_basepath_and_path(path)
parent_dir = self.get_node(parent)
del parent_dir._nodes[name]
def move(self, source, destination):
try:
destination_node = self.get_node(destination)
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError()
try:
source_node = self.get_node(source)
except NodeDoesNotExistError:
raise SourceNodeDoesNotExistError()
if not destination_node.is_directory:
raise DestinationNotADirectoryError()
parent, name = self.get_basepath_and_path(source)
if destination_node.contains_path(name):
raise DestinationNodeExistsError()
destination_node._nodes[name] = source_node
parent_source = self.get_node(parent)
del parent_source._nodes[name]
def link(self, source, destination, symbolic=True):
try:
source_node = self.get_node(source)
except NodeDoesNotExistError:
if symbolic:
raise
else:
raise SourceNodeDoesNotExistError()
if source_node.is_directory and not symbolic:
raise DirectoryHardLinkError()
if symbolic:
node = Symlink(source, self)
else:
node = File(destination, "", self)
node._content = source_node._content
source_node.hard_links_count += 1
node.hard_links_count = source_node.hard_links_count
parent, name = self.get_basepath_and_path(destination)
parent_node = self.get_node(parent)
parent_node._nodes[name] = node
def mount(self, file_system, path):
try:
destination = self.get_node(path)
except NodeDoesNotExistError:
raise MountPointDoesNotExistError
if not destination.is_directory:
raise MountPointNotADirectoryError()
if len(destination.nodes) > 0:
raise MountPointNotEmptyError()
parent, name = self.get_basepath_and_path(path)
parent_node = self.get_node(parent)
parent_node._nodes[name] = file_system
def unmount(self, path):
self.get_node(path)
parent, name = self.get_basepath_and_path(path)
parent_node = self.get_node(parent)
if not parent_node._nodes[name].is_filesystem():
raise NotAMountpointError()
del parent_node._nodes[name]
parent_node._nodes[name] = Dir("mnt")
class FileSystemError(Exception):
pass
class NodeDoesNotExistError(FileSystemError):
pass
class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
pass
class SourceNodeDoesNotExistError(NodeDoesNotExistError):
pass
class NotEnoughSpaceError(FileSystemError):
pass
class DestinationNodeExistsError(FileSystemError):
pass
class NonExplicitDirectoryDeletionError(FileSystemError):
pass
class NonEmptyDirectoryDeletionError(FileSystemError):
pass
class DestinationNotADirectoryError(FileSystemError):
pass
class LinkPathError(FileSystemError):
pass
class DirectoryHardLinkError(FileSystemError):
pass
class FileSystemMountError(FileSystemError):
pass
class MountPointNotEmptyError(FileSystemMountError):
pass
class MountPointNotADirectoryError(FileSystemMountError):
pass
class MountPointDoesNotExistError(FileSystemMountError):
pass
class NotAMountpointError(FileSystemMountError):
pass

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

.............E.EE.
======================================================================
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_remove_nonempty_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.182s

FAILED (errors=3)

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

Димитър обнови решението на 30.04.2015 16:26 (преди над 9 години)

+class Dir:
+ def __init__(self, name):
+ self.name = name
+ self._nodes = {}
+ self.is_directory = True
+
+ def __contains__(self, node):
+ return node in self._nodes.values()
+
+ def is_filesystem(self):
+ return False
+
+ @property
+ def directories(self):
+ nodes = list(filter(lambda x: not x.is_filesystem(),
+ self._nodes.values()))
+ return [node for node in nodes if node.is_directory]
+
+ @property
+ def files(self):
+ nodes = list(filter(lambda x: not x.is_filesystem(),
+ self._nodes.values()))
+ return [node for node in nodes
+ if not node.is_directory]
+
+ @property
+ def nodes(self):
+ return list(self._nodes.values())
+
+ @property
+ def size(self):
+ return (1 + sum([node.size for node in self.directories]) +
+ sum([node.real_size for node in self.files]))
+
+ def contains_path(self, path):
+ return path in self._nodes
+
+
+class File():
+ def __init__(self, name, content, fs):
+ self.name = name
+ self.encoding = "utf-8"
+ self._content = bytearray(content, self.encoding)
+ self.hard_links_count = 1
+ self.is_directory = False
+ self.fs = fs
+
+ @property
+ def size(self):
+ return len(self._content) + 1
+
+ @property
+ def real_size(self):
+ return len(self._content)/self.hard_links_count + 1
+
+ @property
+ def content(self):
+ return self._content.decode(self.encoding)
+
+ def is_filesystem(self):
+ return False
+
+ def append(self, text):
+ if self.fs.available_size + len(text) > self.fs.size:
+ raise NotEnoughSpaceError()
+ self._content.extend(bytearray(text, self.encoding))
+
+ def truncate(self, text):
+ if self.fs.available_size - self.size + len(text) + 1 > self.fs.size:
+ raise NotEnoughSpaceError()
+ self._content.clear()
+ self._content.extend(bytearray(text, self.encoding))
+
+
+class Symlink:
+ def __init__(self, link, fs):
+ self.link_path = link
+ self.size = 1
+ self.fs = fs
+ self.is_directory = fs.get_node(link).is_directory
+
+ def is_filesystem(self):
+ return False
+
+ @property
+ def real_size(self):
+ return self.size
+
+ def __getattr__(self, name):
+ try:
+ node = self.fs.get_node(self.link_path)
+ except NodeDoesNotExistError:
+ raise LinkPathError
+
+ return getattr(node, name)
+
+
+class FileSystem:
+ def __init__(self, size, dir_separator='/'):
+ if size <= 0:
+ raise NotEnoughSpaceError()
+
+ self.size = size
+ self.dir_separator = dir_separator
+ self.root = Dir(self.dir_separator)
+
+ @property
+ def available_size(self):
+ return int(self.size - self.root.size)
+
+ def is_filesystem(self):
+ return True
+
+ def split_path(self, path):
+ return [segment for segment in path.split(self.dir_separator)
+ if segment != '']
+
+ def get_basepath_and_path(self, path_):
+ split_path = self.split_path(path_)
+ path = split_path[-1]
+ base_path = self.dir_separator.join(split_path[:-1])
+ if len(base_path.strip()) == 0:
+ base_path = self.dir_separator
+ return (base_path, path)
+
+ def get_node(self, path):
+ if len(path.strip()) == 0:
+ raise NodeDoesNotExistError
+
+ if len(path.strip().replace(self.dir_separator, "")) == 0:
+ return self.root
+
+ current = self.root
+ segments = self.split_path(path)
+
+ for segment in segments:
+ if current.contains_path(segment):
+ current = current._nodes[segment]
+ if current.is_filesystem():
+ current = current.root
+ else:
+ raise NodeDoesNotExistError('"{}" does not exist'.format(path))
+
+ return current
+
+ def create(self, path, directory=False, content=''):
+ node = None
+ parent, name = self.get_basepath_and_path(path)
+ node = Dir(name) if directory else File(name, content, self)
+
+ if self.available_size - node.size < 0:
+ raise NotEnoughSpaceError()
+
+ try:
+ destination = self.get_node(parent)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ if destination.contains_path(name):
+ raise DestinationNodeExistsError()
+
+ destination._nodes[name] = node
+
+ def remove(self, path, directory=False, force=True):
+ node = self.get_node(path)
+ if node.is_directory and not directory:
+ raise NonExplicitDirectoryDeletionError()
+
+ if node.is_directory and not force and len(node.nodes) != 0:
+ raise NonEmptyDirectoryDeletionError()
+
+ parent, name = self.get_basepath_and_path(path)
+ parent_dir = self.get_node(parent)
+ del parent_dir._nodes[name]
+
+ def move(self, source, destination):
+ try:
+ destination_node = self.get_node(destination)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError()
+
+ if not destination_node.is_directory:
+ raise DestinationNotADirectoryError()
+
+ parent, name = self.get_basepath_and_path(source)
+ if destination_node.contains_path(name):
+ raise DestinationNodeExistsError()
+
+ destination_node._nodes[name] = source_node
+ parent_source = self.get_node(parent)
+ del parent_source._nodes[name]
+
+ def link(self, source, destination, symbolic=True):
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ if symbolic:
+ raise
+ else:
+ raise SourceNodeDoesNotExistError()
+
+ if source_node.is_directory and not symbolic:
+ raise DirectoryHardLinkError()
+
+ if symbolic:
+ node = Symlink(source, self)
+ else:
+ node = File(destination, "", self)
+ node._content = source_node._content
+ source_node.hard_links_count += 1
+ node.hard_links_count = source_node.hard_links_count
+
+ parent, name = self.get_basepath_and_path(destination)
+ parent_node = self.get_node(parent)
+ parent_node._nodes[name] = node
+
+ def mount(self, file_system, path):
+ try:
+ destination = self.get_node(path)
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError
+
+ if not destination.is_directory:
+ raise MountPointNotADirectoryError()
+
+ if len(destination.nodes) > 0:
+ raise MountPointNotEmptyError()
+
+ parent, name = self.get_basepath_and_path(path)
+ parent_node = self.get_node(parent)
+ parent_node._nodes[name] = file_system
+
+ def unmount(self, path):
+ self.get_node(path)
+ parent, name = self.get_basepath_and_path(path)
+ parent_node = self.get_node(parent)
+ if not parent_node._nodes[name].is_filesystem():
+ raise NotAMountpointError()
+
+ del parent_node._nodes[name]
+ parent_node._nodes[name] = Dir("mnt")
+
+
+class FileSystemError(Exception):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+
+class FileSystemMountError(FileSystemError):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+
+class NotAMountpointError(FileSystemMountError):
+ pass