Python Forum
Mirroring disk structures in nested dictionaries
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Mirroring disk structures in nested dictionaries
#11
deanhystad,

Thank you, finally got to code that works.
from pprint import pprint
def get_all_values(obj, level=0):                   # Not my function
    """Walk through a dictionary of dicts and lists."""
    if type(obj) is dict:
        for key, value in obj.items():
            if type(value) in [dict, list]:
                print('    ' * level, key, sep='')
                level = level + 1
                get_all_values(value, level)
                level = level - 1
            else:
                print('    ' * (level), key, ': ', value, sep='')

    elif type(obj) is list:
        for i, element in enumerate(obj):
            if type(element) in [dict, list]:
                print('    ' * level, i, sep='')
                level = level + 1
                get_all_values(element, level)
                level = level - 1
            else:
                print('    ' * (level), element, sep='')
    else:
        raise ValueError

def add(old, new):                      # function by deanhystad - curbie comment
    """Add new dictionary to old."""
    while True:
        key, value = next(iter(new.items()))
        if key in old:
            old = old[key]
        else:
            old[key] = value
            break
        new = value

dskn = 0                                # alpha micro up to 32mb disk number (16 bit logical disk)
ufd = ['1,2', '1,2', '1,4', '1,4']      # list for user file directories
file = ['BADBLK.SYS', 'AMOSL.DIR', 'AMOSL.INI', 'AMOS32.INI']                    # file name
blocks = [3, 42, 2, 4]                  # list for number of full blocks in file
active = [500, 400, 300, 200]           # list for number of bytes in last block of file
link = [1600, 1500, 1400, 1300]         # list for link to first block of file

dsk = {}                                # create blank dictionary

for i in range(0, 4):                   # loop through adding files
    uuu = ufd[i]
    fff = file[i]
    bbb = blocks[i]
    aaa = active[i]
    lll = link[i]
    add(dsk, {dskn: {uuu: {fff: {"blocks": bbb, "active": aaa, "link": lll}}}})

get_all_values(dsk)



(Oct-01-2024, 05:17 PM)deanhystad Wrote: But before writing this, make sure you need it. I would start this project by writing the code that loops through the entire disk (the part you are putting off). That code may reveal disks, dictionaries and files in an order that naturally lends itself to making a nested dictionary without much effort.

Done before I started this thread.
[1,2]	Link:    127	PW: |      |
[1,3]	Link:   1081	PW: |      |
[1,4]	Link:   2157	PW: |      |
plus 29 more UFDs
*********************************************************
AAA   .BAK   Blocks:      1 Active:      2   Link:   2156
ABC   .LIT   Blocks:     19 Active:     60   Link:   2158
ABCLON.LIT   Blocks:     29 Active:    373   Link:   2177
ABMAST.LIT   Blocks:     17 Active:    370   Link:   2206
ABMON .CMD   Blocks:      1 Active:     54   Link:   2223
ABREAD.LIT   Blocks:      4 Active:    254   Link:   2224
ABRELI.EXP   Blocks:      1 Active:     30   Link:   2228
ABRELI.LIT   Blocks:     21 Active:    454   Link:   2229
ABRELI.OVR   Blocks:     10 Active:    416   Link:   2250
ABRELI.RKT   Blocks:      4 Active:    299   Link:   2260
ABRELI.RTB   Blocks:      4 Active:    228   Link:   2264
ABRELI.SYS   Blocks:     16 Active:    122   Link:   2268
ABRND .LIT   Blocks:      5 Active:     20   Link:   2284
plus 1400 more full file specs distributed among the UFDs
Now on to studying your 'add' function to try to figure out where I goofed up.
Reply
#12
Why do you do this:
for i in range(0, 4):                   # loop through adding files
    uuu = ufd[i]
    fff = file[i]
    bbb = blocks[i]
    aaa = active[i]
    lll = link[i]
    add(dsk, {dskn: {uuu: {fff: {"blocks": bbb, "active": aaa, "link": lll}}}})
instead of this:
for i in range(0, 4):                   # loop through adding files
    add(dsk, {dskn: {ufd[i]: {file[i]: {"blocks": blocks[i], "active": active[i], "link": link[i]}}}})
Reply
#13
Because, I find it easier to read and debug while learning a new language, when everything works as intended, I can compress for speed and fewer lines.
Reply
#14
Over the last 50 years I’ve learned maybe a dozen programming languages, but python nested dictionaries is the first programming language concept that has frustrated me, the concept is simple enough, but working with them is frustrating, deanhystad posted an “add” function which functioned perfectly for everything but my understanding of working with them.

Now, I need to push the program I used deanhystad’s “add” function for, and start to chart the porting of my Alpha Micro disassembler to python because of the speed advantages of modern computers over a 8mhz 68000. Which brings me back to properly understanding nested dictionaries.

I went back to scratch just two dictionaries one for the logical disk name (‘dsk0’), and the second for the directories on that logical disk (‘dsk0’: {‘1,2’: 1}). The is typically about 25 directories on a logical disk, but could be many more.

Currently I’m building the nested directories by first starting one logical disk, then adding all directories on that logical disk, then all file names and their attributes for the first directory, before repeating for the next directories. Lastly, checking for another logical disk and repeating if found, halting if not.

Don’t know where I’m goofing up, my screwed up brain throws fits and kills my focus any time I try to code something with code I can’t visualize in my head.
[/python]
fs = {'dsk0': {}}                       # device name paired with empty dictionary

fs['dsk0'] = {'1,2': {}}                # add 1,2
fs['dsk0'] = {'1,4': {}}                # add 1,4
fs['dsk0'] = {'1,6': {}}                # add 1,6
print(fs)                               # print file system dictionaries
Output:
{'dsk0': {'1,6': {}}}
It seems apparent that my attempt to add an element is just changing the same element.

How do I add a (directory) dictionary nested a to logical disk directory?
Reply
#15
You keep changing the value for fs['dsk0']

Do this instead
fs = {"dsk0": {}}  # device name paired with empty dictionary
fs["dsk0"]["1,2"] = {}
fs["dsk0"]["1,4"] = {}
fs["dsk0"]["1,6"] = {}
print(fs)
Output:
{'dsk0': {'1,2': {}, '1,4': {}, '1,6': {}}}
Reply
#16
Thanks deanhystad,

Your output pointed me to my issue, now everything works correctly on two nested dictionaries, after I play with this some more, I should be able to nest two more dictionaries for files and file attributes. After a little more tweaking, I was able to load the nested dictionary from variables:

dnam = 'dsk0'                           # variable for storage device name (dsk0 only)
ufd = ['1,2', '1,4', '1,6']             # list for user file directories (for dsk0 only)
fs = {'dsk0': {}}                       # device name paired with empty dictionary

for x in ufd:                           # loop through directories
    fs[dnam][x] = {}                    # add directory to dsk0 logical disk 'dsk0'
    print(fs)                           # print directory progression

print(fs)                               # print finished file system dictionaries
The finial output seems the same as yours:
Output:
{'dsk0': {'1,2': {}}} {'dsk0': {'1,2': {}, '1,4': {}}} {'dsk0': {'1,2': {}, '1,4': {}, '1,6': {}}} {'dsk0': {'1,2': {}, '1,4': {}, '1,6': {}}}
Reply
#17
This may interest you. In particular the __setitem__ part that builds a directory structure while adding files.
class File:
    """Represents a file in a file system."""
    def __init__(self, content, name='', folder=None):
        self.content = content
        self.name = name
        self.folder = None
        if folder:
            folder.add(self)

    def move(self, folder, name=None):
        """Move to new location."""
        if self.folder:
            self.folder.remove(self)
        if name:
            self.name = name
        folder.add(self, self.name)

    def path(self):
        """Return path as list of folders."""
        path = [self]
        folder = self.folder
        while folder:
            path.insert(0, folder)
            folder = folder.folder
        return path

    def path_str(self):
        """Return path as str."""
        return '/'.join(map(str, self.path()))

    def __str__(self):
        """Return pretty str."""
        return self.name

    def __repr__(self):
        """Return descriptive str."""
        return f"<{self.__class__.__name__} {self.name} in {self.folder}>"

    def __lt__(self, other):
        """For sorting."""
        return str(self) < str(other)


class Folder(File):
    """A special file who's content is a list of files and folders."""
    def __init__(self, name='', folder=None):
        super().__init__({}, name, folder)

    def add(self, file, name=None):
        """Add file to folder."""
        if file.folder:
            file.folder.remove(file)
        if name is not None:
            file.name = name
        file.folder = self
        self.content[file.name] = file

    def remove(self, file):
        """Remove file from folder."""
        if file.name in self.content:
            self.content.pop(file.name)
            file.folder = None

    def __getitem__(self, path):
        """Get file/folder using relative path."""

        def get(folder, part):
            """Return folder[part]."""
            if part == '..':
                return folder.folder
            return folder.content[part]

        file = self
        for part in path.split('/'):
            file = get(file, part)
        return file

    def __setitem__(self, path, file):
        """Add file to folder using relative path.  Builds path if required."""

        def get(folder, part):
            """Return folder[part].  Create folder if not found."""
            if part == '..':
                return folder.folder
            elif part in folder.content:
                return folder.content[part]
            return Folder(part, folder)

        folder = self
        parts = path.split('/')
        for part in parts[:-1]:
            folder = get(folder, part)
        folder.add(file, parts[-1])

    def __iter__(self):
        """Iterate through file names."""
        return iter(self.content)

    def walk(self):
        """Walk through the folder and subfolder returning files."""
        for file in self.content.values():
            if isinstance(file, Folder):
                for subfile in file.walk():
                    yield subfile
            else:
                yield file


root = Folder("")
root["A/B/C/file1"] = File(1)
root["A/B/file2"] = File(2)
root["A/B/file3"] = File(3)
root["D/file4"] = File(4)
a = root["A"]
b = a["B"]
c = b["C"]
d = root["D"]
print("root:", *root.content)
print("/A:", *a.content)
print("/A/B:", *b.content)
print("/A/B/C:", *c.content)
print("/D:", *d.content)
print("/D[../A/B/file3]:", d["../A/B/file3"])
for file in root.walk():
    print(file.path_str(), "content =", file.content)
Output:
root: A D /A: B /A/B: C file2 file3 /A/B/C: file1 /D: file4 /D[../A/B/file3]: file3 /A/B/C/file1 content = 1 /A/B/file2 content = 2 /A/B/file3 content = 3 /D/file4 content = 4
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Nested Lists & Dictionaries Hudjefa 5 1,389 Sep-23-2024, 08:20 PM
Last Post: DeaD_EyE
  DEC pack, unpack and disk-images Curbie 32 7,263 Aug-23-2024, 03:37 PM
Last Post: Curbie
  Windows Disk Cleanup Code Help Needed nal2us2 3 1,082 Jul-19-2024, 04:03 AM
Last Post: deanhystad
  Hard disk structure like a file selection dialog malonn 2 1,764 Aug-09-2023, 09:14 PM
Last Post: malonn
  Searching through Nested Dictionaries and Lists Dave_London 1 11,745 Jul-09-2020, 03:36 PM
Last Post: mrdominikku
  ctypes and custom data type (structures, pointer to structures) python_user_n 0 3,904 Jul-08-2020, 05:52 PM
Last Post: python_user_n
  How to Calculate CPU, Disk, Memory and Network utilization rate skvivekanand 1 2,658 Jun-16-2020, 08:53 PM
Last Post: jefsummers
  Creating Nested Dictionaries Confusion gw1500se 2 2,866 May-18-2020, 11:16 PM
Last Post: gw1500se
  how to write offset number to disk use python? Pyguys 4 4,225 Apr-11-2020, 07:53 AM
Last Post: Pyguys
  Finding value in nested dictionaries with lists mart79 16 18,835 Mar-08-2020, 08:16 PM
Last Post: ndc85430

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020