Search code examples
pythondictionarykeyerror

Weird KeyError || Python3.6.1


I am trying to make something like FileSystem in python. My goal is to make files which can contain some data and Directories which can contain some files. Then I have some simple commands

  • cd

  • ls

  • mk_dir

  • mk_file

So, now I have a problem with this: There's DirectoryBase class which is different from Directory, because it has no ParentDir (Directory in that is File/Directory saved). Then there's Directory class that extends DirectoryBase and overwrites path() method (method returning path to file/dir) and data dict has another default key: '..', but when I am trying to find it in data dict it raises KeyError. Another weird thing, about it is that I am testing if file/dir exists, and if not it will return, so I don't know how this is possible, that it got KeyError.

This is my code:

class AttributeDictionary(dict):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.__getattr__ = self.__getitem__
        self.__setattr__ = self.__setitem__
        self.__delattr__ = self.__delitem__


class FileManager(object):
    def __init__(self):
        self.disk_dir = DirectoryBase('__disk__')
        self.current_dir = self.disk_dir

    def _find(self, path):
        """ Gets file/dir object using path """
        _cd = self.current_dir
        for part in path:
            _cd = _cd[part]
        return _cd

    def cmd_cd(self, path):
        """ Classic unix `cd` command """
        f = self._find(path)
        if f is DirectoryBase:
            self.current_dir = f
        else:
            return FileSystemError('DirectoryNotFound')

    def cmd_ls(self):
        """ Classic unix `ls` command """
        return ConsoleOutput(''.join([f'{i}\n' for i in self.current_dir.data]))

    def cmd_mkfile(self, name):
        """ file making command """
        self.current_dir.__setitem__(name, File(name, self.current_dir))

    def cmd_mkdir(self, name):
        """ file making command """
        self.current_dir.__setitem__(name, Directory(name, self.current_dir))


class File(object):
    def __init__(self, name, pd):
        self.data = [0x00]
        self.name = name
        self.pd = pd

    def path(self):
        return [self.name] + self.pd.path()

    def __sizeof__(self):
        return len(self.data)


class DirectoryBase(AttributeDictionary):
    def __init__(self, name, **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.data = {'.': self}

    def path(self):
        return self.name

    def __getitem__(self, item):
        if item in self.data.keys():
            return FileSystemError('FileNotFound')
        return self.data[item] # KeyError: '..' found here

    def __setitem__(self, key, value):
        if key in self.data.keys():
            return FileSystemError('FileAlreadyExists')
        self.data[key] = value

    def __delitem__(self, key):
        if key in self.data.keys():
            return FileSystemError('FileNotFound')
        self.data.__delitem__(key)


class Directory(DirectoryBase):
    def __init__(self, name, pd, **kwargs):
        super().__init__(name, **kwargs)
        self.pd = pd
        self.data = {'.': self, '..': self.pd}

    def path(self):
        return [self.name] + self.pd.path()


if __name__ == '__main__':
    fs = FileManager()
    fs.cmd_mkdir('test')
    print(fs.cmd_ls())
    fs.cmd_cd(['test'])
    fs.cmd_mkfile('idk.txt')
    print(fs.cmd_ls())
    fs.cmd_cd(['..'])
    print(fs.cmd_ls())

Error looks like this:

.
test
Traceback (most recent call last):

.
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 106, in <module>
test
    fs.cmd_cd(['..'])
idk.txt

  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 32, in cmd_cd
    f = self._find(path)
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 27, in _find
    _cd = _cd[part]
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 76, in __getitem__
    return self.data[item]
KeyError: '..'

or when I delete prints:

Traceback (most recent call last):
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 106, in <module>
    fs.cmd_cd(['..'])
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 32, in cmd_cd
    f = self._find(path)
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 27, in _find
    _cd = _cd[part]
  File "/Users/jan/PycharmProjects/Xaon/src/fs.py", line 76, in __getitem__
    return self.data[item]
KeyError: '..'

Sorry if it is too confusing, I am beginner and my English is bad too.


Solution

  • the code logic is flawed:

    def __getitem__(self, item):
        if item in self.data.keys():
            return FileSystemError('FileNotFound')
        return self.data[item] # KeyError: '..' found here
    

    you are throwing an error when the key exists. Just negate the condition (and drop the .keys() which is useless & unpythonic and even a performance killer in Python 2):

    def __getitem__(self, item):
        if item not in self.data:
            return FileSystemError('FileNotFound')
        return self.data[item]
    

    there's the same error in __delitem__ BTW.

    When fixed (and stubbed most of unexisting/unshown classes with str) I get the following output:

    .
    test
    
    .
    idk.txt
    test
    
    .
    idk.txt
    test