Решение на In-memory файлова система от Ангел Ангелов

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

Към профила на Ангел Ангелов

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 13 успешни тест(а)
  • 5 неуспешни тест(а)

Код

from os.path import basename, dirname
from collections import defaultdict
class FileSystemError(RuntimeError):
pass
class NotEnoughSpaceError(FileSystemError):
pass
class NodeDoesNotExistError(FileSystemError):
pass
class SourceNodeDoesNotExistError(NodeDoesNotExistError):
pass
class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
pass
class DestinationNodeExistsError(FileSystemError):
pass
class FileSystemMountError(FileSystemError):
pass
class MountPointDoesNotExistError(FileSystemMountError):
pass
class MountPointNotADirectoryError(FileSystemMountError):
pass
class MountPointNotEmptyError(FileSystemMountError):
pass
class NotAMountpointError(FileSystemMountError):
pass
class NonExplicitDirectoryDeletionError(FileSystemError):
pass
class NonEmptyDirectoryDeletionError(FileSystemError):
pass
class DestinationNotADirectoryError(FileSystemError):
pass
class DirectoryHardLinkError(FileSystemError):
pass
class LinkPathError(FileSystemError):
pass
class Node:
def __init__(self, directory=False, content='', filesystem=None):
self.is_directory = directory
self.real_content = content
self.real_children = {}
self.mountpoint = None
self.link_path = None
self.filesystem = filesystem
def get_path(self, path):
if self.mountpoint:
return self.mountpoint.root.get_path(path)
if not path:
return self
if not self.is_directory:
raise NodeDoesNotExistError
try:
if '/' in path:
root, rest = path.split('/', 1)
return self.children[root].get_path(rest)
else:
return self.children[path].get_path('')
except KeyError:
raise NodeDoesNotExistError
def _linked_node(self):
try:
return self.filesystem.get_node(self.link_path)
except NodeDoesNotExistError:
raise LinkPathError
@property
def content(self):
if self.link_path:
return self._linked_node().content
else:
return self.real_content
@property
def children(self):
if self.link_path:
return self._linked_node().children
else:
return self.real_children
@property
def nodes(self):
return self.children.values()
@property
def directories(self):
return [node for node in self.nodes if node.is_directory]
@property
def files(self):
return [node for node in self.nodes if not node.is_directory]
@property
def size(self):
if self.link_path:
return 1
elif self.is_directory:
return 1 + sum([node.size for node in self.nodes])
else:
if self.filesystem.nlink[id(self.content)] > 1:
return 1
else:
return 1 + len(self.content)
class FileSystem:
def __init__(self, size):
self.size = size
self.available_size = size - 1
self.root = Node(directory=True, filesystem=self)
self.nlink = defaultdict(int)
def get_node(self, path):
if not path:
raise FileSystemError('empty path')
if path[0] != '/':
raise FileSystemError('invalid absolute path')
path = path[1:]
return self.root.get_path(path)
def create(self, path, directory=False, content=''):
node = Node(directory, content, filesystem=self)
try:
parent = self.get_node(dirname(path))
except NodeDoesNotExistError:
raise DestinationNodeDoesNotExistError
if parent.filesystem.available_size < node.size:
raise NotEnoughSpaceError
if not parent.is_directory:
raise FileSystemError('parent not a directory')
filename = basename(path)
if filename in parent.children:
raise DestinationNodeExistsError
parent.children[filename] = node
parent.filesystem.nlink[id(content)] += 1
parent.filesystem.available_size -= node.size
def remove(self, path, directory=False, force=True):
parent = self.get_node(dirname(path))
node = self.get_node(path)
if node.is_directory:
if not directory:
raise NonExplicitDirectoryDeletionError
if node.children and not force:
raise NonEmptyDirectoryDeletionError
del parent.children[basename(path)]
node.filesystem.available_size += node.size
node.filesystem.nlink[id(node.content)] -= 1
def move(self, source, destination):
try:
source_node = self.get_node(source)
except NodeDoesNotExistError:
raise SourceNodeDoesNotExistError
try:
destination_node = self.get_node(destination)
except NodeDoesNotExistError as exception:
raise DestinationNodeDoesNotExistError
if not destination_node.is_directory:
raise DestinationNotADirectoryError
if basename(source) in destination_node.children:
raise DestinationNodeExistsError
destination_node.children[basename(source)] = source_node
del self.get_node(dirname(source)).children[basename(source)]
def hardlink(self, source, destination):
try:
source_node = self.get_node(source)
except NodeDoesNotExistError:
raise SourceNodeDoesNotExistError
if source_node.is_directory:
raise DirectoryHardLinkError
self.create(destination, content=source_node.content)
def symlink(self, source, destination):
source_node = self.get_node(source)
self.create(destination, directory=source_node.is_directory)
destination_node = self.get_node(destination)
destination_node.link_path = source
def link(self, source, destination, symbolic=True):
if symbolic:
self.symlink(source, destination)
else:
self.hardlink(source, destination)
def mount(self, file_system, path):
try:
parent = self.get_node(path)
except NodeDoesNotExistError:
raise MountPointDoesNotExistError
if not parent.is_directory:
raise MountPointNotADirectoryError
if parent.children:
raise MountPointNotEmptyError
parent.mountpoint = file_system
def unmount(self, path):
parent = self.get_node(dirname(path))
try:
node = parent.children[basename(path)]
except KeyError:
raise NodeDoesNotExistError
if not node.mountpoint:
raise NotAMountpointError
node.mountpoint = None

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

..E.....E....E.EE.
======================================================================
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_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

----------------------------------------------------------------------
Ran 18 tests in 10.187s

FAILED (errors=5)

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

Ангел обнови решението на 30.04.2015 00:32 (преди почти 9 години)

+from os.path import basename, dirname
+from collections import defaultdict
+
+class FileSystemError(RuntimeError):
+ pass
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+class FileSystemMountError(FileSystemError):
+ pass
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+class NotAMountpointError(FileSystemMountError):
+ pass
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class Node:
+ def __init__(self, directory=False, content='', filesystem=None):
+ self.is_directory = directory
+ self.real_content = content
+ self.real_children = {}
+ self.mountpoint = None
+ self.link_path = None
+ self.filesystem = filesystem
+
+ def get_path(self, path):
+ if self.mountpoint:
+ return self.mountpoint.root.get_path(path)
+
+ if not path:
+ return self
+
+ if not self.is_directory:
+ raise NodeDoesNotExistError
+
+ try:
+ if '/' in path:
+ root, rest = path.split('/', 1)
+ return self.children[root].get_path(rest)
+ else:
+ return self.children[path].get_path('')
+ except KeyError:
+ raise NodeDoesNotExistError
+
+ def _linked_node(self):
+ try:
+ return self.filesystem.get_node(self.link_path)
+ except NodeDoesNotExistError:
+ raise LinkPathError
+
+ @property
+ def content(self):
+ if self.link_path:
+ return self._linked_node().content
+ else:
+ return self.real_content
+
+ @property
+ def children(self):
+ if self.link_path:
+ return self._linked_node().children
+ else:
+ return self.real_children
+
+ @property
+ def nodes(self):
+ return self.children.values()
+
+ @property
+ def directories(self):
+ return [node for node in self.nodes if node.is_directory]
+
+ @property
+ def files(self):
+ return [node for node in self.nodes if not node.is_directory]
+
+ @property
+ def size(self):
+ if self.link_path:
+ return 1
+ elif self.is_directory:
+ return 1 + sum([node.size for node in self.nodes])
+ else:
+ if self.filesystem.nlink[id(self.content)] > 1:
+ return 1
+ else:
+ return 1 + len(self.content)
+
+class FileSystem:
+ def __init__(self, size):
+ self.size = size
+ self.available_size = size - 1
+ self.root = Node(directory=True, filesystem=self)
+ self.nlink = defaultdict(int)
+
+ def get_node(self, path):
+ if not path:
+ raise FileSystemError('empty path')
+ if path[0] != '/':
+ raise FileSystemError('invalid absolute path')
+ path = path[1:]
+
+ return self.root.get_path(path)
+
+ def create(self, path, directory=False, content=''):
+ node = Node(directory, content, filesystem=self)
+ try:
+ parent = self.get_node(dirname(path))
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError
+
+ if parent.filesystem.available_size < node.size:
+ raise NotEnoughSpaceError
+
+ if not parent.is_directory:
+ raise FileSystemError('parent not a directory')
+
+ filename = basename(path)
+ if filename in parent.children:
+ raise DestinationNodeExistsError
+
+ parent.children[filename] = node
+ parent.filesystem.nlink[id(content)] += 1
+ parent.filesystem.available_size -= node.size
+
+ def remove(self, path, directory=False, force=True):
+ parent = self.get_node(dirname(path))
+ node = self.get_node(path)
+
+ if node.is_directory:
+ if not directory:
+ raise NonExplicitDirectoryDeletionError
+ if node.children and not force:
+ raise NonEmptyDirectoryDeletionError
+
+ del parent.children[basename(path)]
+ node.filesystem.available_size += node.size
+ node.filesystem.nlink[id(node.content)] -= 1
+
+ def move(self, source, destination):
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError
+
+ try:
+ destination_node = self.get_node(destination)
+ except NodeDoesNotExistError as exception:
+ raise DestinationNodeDoesNotExistError
+
+ if not destination_node.is_directory:
+ raise DestinationNotADirectoryError
+
+ if basename(source) in destination_node.children:
+ raise DestinationNodeExistsError
+
+ destination_node.children[basename(source)] = source_node
+ del self.get_node(dirname(source)).children[basename(source)]
+
+ def hardlink(self, source, destination):
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError
+
+ if source_node.is_directory:
+ raise DirectoryHardLinkError
+
+ self.create(destination, content=source_node.content)
+
+ def symlink(self, source, destination):
+ source_node = self.get_node(source)
+ self.create(destination, directory=source_node.is_directory)
+ destination_node = self.get_node(destination)
+ destination_node.link_path = source
+
+ def link(self, source, destination, symbolic=True):
+ if symbolic:
+ self.symlink(source, destination)
+ else:
+ self.hardlink(source, destination)
+
+ def mount(self, file_system, path):
+ try:
+ parent = self.get_node(path)
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError
+ if not parent.is_directory:
+ raise MountPointNotADirectoryError
+ if parent.children:
+ raise MountPointNotEmptyError
+
+ parent.mountpoint = file_system
+
+ def unmount(self, path):
+ parent = self.get_node(dirname(path))
+ try:
+ node = parent.children[basename(path)]
+ except KeyError:
+ raise NodeDoesNotExistError
+
+ if not node.mountpoint:
+ raise NotAMountpointError
+
+ node.mountpoint = None