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

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

Към профила на Красимир Николов

Резултати

  • 7 точки от тестове
  • 0 бонус точки
  • 7 точки общо
  • 11 успешни тест(а)
  • 7 неуспешни тест(а)

Код

class FileSystemError(Exception):
pass
class FileSystemMountError(FileSystemError):
pass
class NodeDoesNotExistError(FileSystemError):
pass
class DestinationNodeExistsError(FileSystemError):
pass
class SourceNodeDoesNotExistError(NodeDoesNotExistError):
pass
class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
pass
class MountPointDoesNotExistError(FileSystemMountError):
pass
class MountPointNotADirectoryError(FileSystemMountError):
pass
class MountPointNotEmptyError(FileSystemMountError):
pass
class NotEnoughSpaceError(FileSystemError):
pass
class NonEmptyDirectoryDeletionError(FileSystemError):
pass
class NonExplicitDirectoryDeletionError(FileSystemError):
pass
class DestinationNotADirectoryError(FileSystemError):
pass
class DirectoryHardLinkError(FileSystemError):
pass
class LinkPathError(FileSystemError):
pass
class FileSystem:
def __init__(self, size):
self.__size = size
self.__available_size = size - 1
if self.__available_size < 0:
raise NotEnoughSpaceError
self.directory_obj = Directory('/')
self.file_obj = File()
self.all_nodes = {'/': self.directory_obj}
@property
def size(self):
return self.__size
@property
def available_size(self):
return self.__available_size
def get_node(self, path):
try:
if type(self.all_nodes[path]) is dict:
return self.all_nodes[path]['data']
return self.all_nodes[path]
except KeyError:
raise NodeDoesNotExistError
def create(self, path, directory=False, content=''):
if directory:
self.__check_errors_for_directory(path)
old_path = path
path = FileSystem.format_path(path)
directory = self.directory_obj.create(path)
self.all_nodes[old_path] = directory
self.__available_size -= 1
else:
file_size = len(content)
self.__check_errors_for_file(path, file_size + 1)
file_details = File(path, content, self)
self.all_nodes[path] = file_details
self.__available_size -= file_size + 1
def remove(self, path, directory=False, force=True):
pd = FileSystem.format_path_to_parent_directory(path)
parent_directory = pd[0]
try:
if type(self.all_nodes[path]) is Directory:
if directory:
self.all_nodes[parent_directory].remove(path, force)
for_remove = FileSystem.slice_dict(self.all_nodes, path)
sizes = self.get_all_size_for_free(for_remove)
self.__remove_tree(for_remove)
self.__available_size += sizes
else:
raise NonExplicitDirectoryDeletionError
else:
self.all_nodes[path].remove(path)
self.__available_size += self.all_nodes[path].size
del self.all_nodes[path]
except KeyError:
raise NodeDoesNotExistError
def move(self, source, destination):
self.__check_errors_for_move(source, destination)
path = FileSystem.format_path_to_parent_directory(source)
parent_source = self.get_node(path[0])
source_item = self.get_node(source)
destination_item = self.get_node(destination)
destination_item.move(source_item)
parent_source.remove(source_item.path, force=True)
if type(source_item) is Directory:
for_rename = self.slice_dict(self.all_nodes, source + '/')
for_rename[source] = self.all_nodes[source]
self.__remove_tree(for_rename)
names = self.__get_new_names(for_rename, path[0], destination)
self.all_nodes.update(names)
else:
new_key = destination + '/' + path[1]
self.all_nodes[new_key] = self.all_nodes.pop(source)
self.all_nodes[new_key].path = new_key
# TODO: Implement
def link(self, source, destination, symbolic=True):
self.__check_errors_for_link(source, symbolic)
if symbolic:
self.all_nodes[destination] = {
'data': self.all_nodes[source],
'source': source,
}
self.__available_size -= 1
def mount(self, file_system, path):
self.__cehck_exception_for_mount(path)
self.all_nodes[path] = file_system
self.__available_size -= 1
@staticmethod
def get_all_size_for_free(for_remove):
size = 0
for value in for_remove.values():
size += value.size
return size
@staticmethod
def check_available_size(available_size, size_decrement):
if (available_size - size_decrement) < 0:
raise NotEnoughSpaceError
@staticmethod
def format_path(path):
new_path = path.split('/')
new_path[0] = '/'
return new_path
@staticmethod
def format_path_to_parent_directory(path):
new_path = path.rsplit('/', 1)
if new_path[0] == '':
new_path[0] = '/'
return new_path
def format_path_to_rename_key(self, path, split_word):
new_path = path.split(split_word, 1)
return new_path
@staticmethod
def slice_dict(d, s):
return {k: v for k, v in d.items() if k.startswith(s)}
def __check_errors_for_file(self, path, size):
self.__check_general_errors(path)
FileSystem.check_available_size(self.__available_size, size)
def __check_errors_for_directory(self, path):
self.__check_general_errors(path)
FileSystem.check_available_size(self.__available_size, 1)
def __check_errors_for_move(self, source, destination):
if source not in self.all_nodes.keys():
raise SourceNodeDoesNotExistError
if destination not in self.all_nodes.keys():
raise DestinationNodeDoesNotExistError
if type(self.all_nodes[destination]) is not Directory:
raise DestinationNotADirectoryError
path = FileSystem.format_path_to_parent_directory(source)
if destination == '/':
destination = destination + path[1]
else:
destination = destination + '/' + path[1]
if destination in self.all_nodes.keys():
raise DestinationNodeExistsError
def __check_errors_for_link(self, source, symbolic):
if source not in self.all_nodes.keys() and symbolic:
raise NodeDoesNotExistError
if not symbolic:
try:
self.all_nodes[source]
except KeyError:
raise SourceNodeDoesNotExistError
if not symbolic and type(self.all_nodes[source]) is Directory:
raise DirectoryHardLinkError
def __check_general_errors(self, path):
if path in self.all_nodes.keys():
raise DestinationNodeExistsError
path = FileSystem.format_path_to_parent_directory(path)
if path[0] not in self.all_nodes.keys():
raise DestinationNodeDoesNotExistError
def __get_new_names(self, old_nodes, parent_path, destination):
new_nodes = {}
for key, value in old_nodes.items():
continue_name = self.format_path_to_rename_key(key, parent_path)
new_path = destination + continue_name[1]
new_nodes[new_path] = value
new_nodes[new_path].path = new_path
return new_nodes
def __cehck_exception_for_mount(self, path):
if path not in self.all_nodes.keys():
raise MountPointDoesNotExistError
if type(self.all_nodes[path]) is File:
raise MountPointNotADirectoryError
if not self.all_nodes[path].is_empty():
raise MountPointNotEmptyError
def __remove_tree(self, for_remove):
for key in for_remove.keys():
del self.all_nodes[key]
class Directory:
def __init__(self, path):
self.__is_directory = True
self.__sub_directory = []
self.__sub_files = []
self.__path = path
@property
def path(self):
return self.__path
@property
def is_directory(self):
return self.__is_directory
@property
def directories(self):
return self.__sub_directory
@property
def files(self):
return self.__sub_files
@property
def nodes(self):
return self.__sub_directory + self.__sub_files
@property
def size(self):
return 1
@files.setter
def files(self, file):
self.__sub_files.append(file)
@path.setter
def path(self, path):
self.__path = path
def is_empty(self):
if len(self.__sub_files) == 0 and len(self.__sub_directory) == 0:
return True
return False
def create(self, path):
parent_directory = self.__destination_folder(path)
directory_path = Directory.get_correct_directory_path(path)
new_directory = Directory(directory_path)
parent_directory.__sub_directory.append(new_directory)
return new_directory
def remove(self, path, force=False):
child_directory = None
for counter, directory in enumerate(self.__sub_directory):
if directory.path == path:
child_directory = self.__sub_directory[counter]
break
if force is False and\
(len(child_directory.__sub_files) != 0 or
len(child_directory.__sub_directory) != 0):
raise NonEmptyDirectoryDeletionError
self.__sub_directory.remove(child_directory)
def remove_file(self, file):
self.__sub_files.remove(file)
def move(self, sources):
if type(sources) is Directory:
self.__sub_directory.append(sources)
elif type(sources) is File:
self.__sub_files.append(sources)
def __destination_folder(self, path):
if len(path) == 1:
return self
directory_path = Directory.construct_path(path)
for directory in self.__sub_directory:
if directory_path == directory.path:
path[0] = Directory.construct_path(path)
del path[1]
return directory.__destination_folder(path)
return self
@staticmethod
def get_correct_directory_path(path):
if path[0] == '/':
directory_path = '/' + '/'.join(path[1:])
else:
directory_path = '/'.join(path)
return directory_path
@staticmethod
def construct_path(path):
if path[0] == '/':
return path[0] + path[1]
return path[0] + '/' + path[1]
class File:
def __init__(self, path=None, content=None, file_system=None):
self.__content = content
self.__path = path
self.__fs = file_system
self.__insert_in_correct_directory(path)
self.__is_directory = False
@property
def is_directory(self):
return self.__is_directory
@property
def content(self):
return self.__content
@property
def size(self):
return len(self.__content) + 1
@property
def path(self):
return self.__path
@path.setter
def path(self, path):
self.__path = path
def append(self, content):
self.__content += content
def truncate(self, content):
self.__content = content
def remove(self, path):
new_path = FileSystem.format_path_to_parent_directory(path)
node = self.__fs.get_node(new_path[0])
node.remove_file(self)
def __insert_in_correct_directory(self, path=None):
if path is not None:
path = FileSystem.format_path_to_parent_directory(path)
node = self.__fs.get_node(path[0])
node.files = self

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

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

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

======================================================================
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_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

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

----------------------------------------------------------------------
Ran 18 tests in 14.172s

FAILED (errors=7)

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

Красимир обнови решението на 30.04.2015 09:19 (преди почти 9 години)

+class FileSystemError(Exception):
+ pass
+
+
+class FileSystemMountError(FileSystemError):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class FileSystem:
+ def __init__(self, size):
+ self.__size = size
+ self.__available_size = size - 1
+ if self.__available_size < 0:
+ raise NotEnoughSpaceError
+ self.directory_obj = Directory('/')
+ self.file_obj = File()
+ self.all_nodes = {'/': self.directory_obj}
+
+ @property
+ def size(self):
+ return self.__size
+
+ @property
+ def available_size(self):
+ return self.__available_size
+
+ def get_node(self, path):
+ try:
+ if type(self.all_nodes[path]) is dict:
+ return self.all_nodes[path]['data']
+ return self.all_nodes[path]
+ except KeyError:
+ raise NodeDoesNotExistError
+
+ def create(self, path, directory=False, content=''):
+ if directory:
+ self.__check_errors_for_directory(path)
+ old_path = path
+ path = FileSystem.format_path(path)
+ directory = self.directory_obj.create(path)
+ self.all_nodes[old_path] = directory
+ self.__available_size -= 1
+ else:
+ file_size = len(content)
+ self.__check_errors_for_file(path, file_size + 1)
+ file_details = File(path, content, self)
+ self.all_nodes[path] = file_details
+ self.__available_size -= file_size + 1
+
+ def remove(self, path, directory=False, force=True):
+ pd = FileSystem.format_path_to_parent_directory(path)
+ parent_directory = pd[0]
+ try:
+ if type(self.all_nodes[path]) is Directory:
+ if directory:
+ self.all_nodes[parent_directory].remove(path, force)
+ for_remove = FileSystem.slice_dict(self.all_nodes, path)
+ sizes = self.get_all_size_for_free(for_remove)
+ self.__remove_tree(for_remove)
+ self.__available_size += sizes
+ else:
+ raise NonExplicitDirectoryDeletionError
+ else:
+ self.all_nodes[path].remove(path)
+ self.__available_size += self.all_nodes[path].size
+ del self.all_nodes[path]
+ except KeyError:
+ raise NodeDoesNotExistError
+
+ def move(self, source, destination):
+ self.__check_errors_for_move(source, destination)
+ path = FileSystem.format_path_to_parent_directory(source)
+ parent_source = self.get_node(path[0])
+ source_item = self.get_node(source)
+ destination_item = self.get_node(destination)
+ destination_item.move(source_item)
+ parent_source.remove(source_item.path, force=True)
+ if type(source_item) is Directory:
+ for_rename = self.slice_dict(self.all_nodes, source + '/')
+ for_rename[source] = self.all_nodes[source]
+ self.__remove_tree(for_rename)
+ names = self.__get_new_names(for_rename, path[0], destination)
+ self.all_nodes.update(names)
+ else:
+ new_key = destination + '/' + path[1]
+ self.all_nodes[new_key] = self.all_nodes.pop(source)
+ self.all_nodes[new_key].path = new_key
+
+ # TODO: Implement
+ def link(self, source, destination, symbolic=True):
+ self.__check_errors_for_link(source, symbolic)
+ if symbolic:
+ self.all_nodes[destination] = {
+ 'data': self.all_nodes[source],
+ 'source': source,
+ }
+ self.__available_size -= 1
+
+ def mount(self, file_system, path):
+ self.__cehck_exception_for_mount(path)
+ self.all_nodes[path] = file_system
+ self.__available_size -= 1
+
+ @staticmethod
+ def get_all_size_for_free(for_remove):
+ size = 0
+ for value in for_remove.values():
+ size += value.size
+ return size
+
+ @staticmethod
+ def check_available_size(available_size, size_decrement):
+ if (available_size - size_decrement) < 0:
+ raise NotEnoughSpaceError
+
+ @staticmethod
+ def format_path(path):
+ new_path = path.split('/')
+ new_path[0] = '/'
+ return new_path
+
+ @staticmethod
+ def format_path_to_parent_directory(path):
+ new_path = path.rsplit('/', 1)
+ if new_path[0] == '':
+ new_path[0] = '/'
+ return new_path
+
+ def format_path_to_rename_key(self, path, split_word):
+ new_path = path.split(split_word, 1)
+ return new_path
+
+ @staticmethod
+ def slice_dict(d, s):
+ return {k: v for k, v in d.items() if k.startswith(s)}
+
+ def __check_errors_for_file(self, path, size):
+ self.__check_general_errors(path)
+ FileSystem.check_available_size(self.__available_size, size)
+
+ def __check_errors_for_directory(self, path):
+ self.__check_general_errors(path)
+ FileSystem.check_available_size(self.__available_size, 1)
+
+ def __check_errors_for_move(self, source, destination):
+ if source not in self.all_nodes.keys():
+ raise SourceNodeDoesNotExistError
+ if destination not in self.all_nodes.keys():
+ raise DestinationNodeDoesNotExistError
+ if type(self.all_nodes[destination]) is not Directory:
+ raise DestinationNotADirectoryError
+ path = FileSystem.format_path_to_parent_directory(source)
+ if destination == '/':
+ destination = destination + path[1]
+ else:
+ destination = destination + '/' + path[1]
+ if destination in self.all_nodes.keys():
+ raise DestinationNodeExistsError
+
+ def __check_errors_for_link(self, source, symbolic):
+ if source not in self.all_nodes.keys() and symbolic:
+ raise NodeDoesNotExistError
+ if not symbolic:
+ try:
+ self.all_nodes[source]
+ except KeyError:
+ raise SourceNodeDoesNotExistError
+ if not symbolic and type(self.all_nodes[source]) is Directory:
+ raise DirectoryHardLinkError
+
+ def __check_general_errors(self, path):
+ if path in self.all_nodes.keys():
+ raise DestinationNodeExistsError
+ path = FileSystem.format_path_to_parent_directory(path)
+ if path[0] not in self.all_nodes.keys():
+ raise DestinationNodeDoesNotExistError
+
+ def __get_new_names(self, old_nodes, parent_path, destination):
+ new_nodes = {}
+ for key, value in old_nodes.items():
+ continue_name = self.format_path_to_rename_key(key, parent_path)
+ new_path = destination + continue_name[1]
+ new_nodes[new_path] = value
+ new_nodes[new_path].path = new_path
+ return new_nodes
+
+ def __cehck_exception_for_mount(self, path):
+ if path not in self.all_nodes.keys():
+ raise MountPointDoesNotExistError
+ if type(self.all_nodes[path]) is File:
+ raise MountPointNotADirectoryError
+ if not self.all_nodes[path].is_empty():
+ raise MountPointNotEmptyError
+
+ def __remove_tree(self, for_remove):
+ for key in for_remove.keys():
+ del self.all_nodes[key]
+
+
+class Directory:
+
+ def __init__(self, path):
+ self.__is_directory = True
+ self.__sub_directory = []
+ self.__sub_files = []
+ self.__path = path
+
+ @property
+ def path(self):
+ return self.__path
+
+ @property
+ def is_directory(self):
+ return self.__is_directory
+
+ @property
+ def directories(self):
+ return self.__sub_directory
+
+ @property
+ def files(self):
+ return self.__sub_files
+
+ @property
+ def nodes(self):
+ return self.__sub_directory + self.__sub_files
+
+ @property
+ def size(self):
+ return 1
+
+ @files.setter
+ def files(self, file):
+ self.__sub_files.append(file)
+
+ @path.setter
+ def path(self, path):
+ self.__path = path
+
+ def is_empty(self):
+ if len(self.__sub_files) == 0 and len(self.__sub_directory) == 0:
+ return True
+ return False
+
+ def create(self, path):
+ parent_directory = self.__destination_folder(path)
+ directory_path = Directory.get_correct_directory_path(path)
+ new_directory = Directory(directory_path)
+ parent_directory.__sub_directory.append(new_directory)
+ return new_directory
+
+ def remove(self, path, force=False):
+ child_directory = None
+
+ for counter, directory in enumerate(self.__sub_directory):
+ if directory.path == path:
+ child_directory = self.__sub_directory[counter]
+ break
+ if force is False and\
+ (len(child_directory.__sub_files) != 0 or
+ len(child_directory.__sub_directory) != 0):
+ raise NonEmptyDirectoryDeletionError
+ self.__sub_directory.remove(child_directory)
+
+ def remove_file(self, file):
+ self.__sub_files.remove(file)
+
+ def move(self, sources):
+ if type(sources) is Directory:
+ self.__sub_directory.append(sources)
+ elif type(sources) is File:
+ self.__sub_files.append(sources)
+
+ def __destination_folder(self, path):
+ if len(path) == 1:
+ return self
+ directory_path = Directory.construct_path(path)
+ for directory in self.__sub_directory:
+ if directory_path == directory.path:
+ path[0] = Directory.construct_path(path)
+ del path[1]
+ return directory.__destination_folder(path)
+ return self
+
+ @staticmethod
+ def get_correct_directory_path(path):
+ if path[0] == '/':
+ directory_path = '/' + '/'.join(path[1:])
+ else:
+ directory_path = '/'.join(path)
+ return directory_path
+
+ @staticmethod
+ def construct_path(path):
+ if path[0] == '/':
+ return path[0] + path[1]
+ return path[0] + '/' + path[1]
+
+
+class File:
+ def __init__(self, path=None, content=None, file_system=None):
+ self.__content = content
+ self.__path = path
+ self.__fs = file_system
+ self.__insert_in_correct_directory(path)
+ self.__is_directory = False
+
+ @property
+ def is_directory(self):
+ return self.__is_directory
+
+ @property
+ def content(self):
+ return self.__content
+
+ @property
+ def size(self):
+ return len(self.__content) + 1
+
+ @property
+ def path(self):
+ return self.__path
+
+ @path.setter
+ def path(self, path):
+ self.__path = path
+
+ def append(self, content):
+ self.__content += content
+
+ def truncate(self, content):
+ self.__content = content
+
+ def remove(self, path):
+ new_path = FileSystem.format_path_to_parent_directory(path)
+ node = self.__fs.get_node(new_path[0])
+ node.remove_file(self)
+
+ def __insert_in_correct_directory(self, path=None):
+ if path is not None:
+ path = FileSystem.format_path_to_parent_directory(path)
+ node = self.__fs.get_node(path[0])
+ node.files = self