maxpat78 / FATtools

Facilities to access (ex)FAT filesystems and disk images with Python 3
39 stars 4 forks source link

sortby not functioning (per sample) #7

Closed bengalih closed 2 years ago

bengalih commented 2 years ago

Having some issues with sortby, so tried to just use example code, substituting just my drive letter:

from FATtools.Volume import *

# Assuming we have DirA, DirB, DirC in this disk order into X:
root = vopen('G:', 'r+b')

new_order = '''DirB
DirC
DirA'''

root._sortby.fix = new_order.split('\n') # uses built-in directory sort algorithm
root.sort(root._sortby) # user-defined order, in _sortby.fix list
root.sort() # default ordering (alphabetical)

Error returned is:

Traceback (most recent call last):
  File "d:\data\labs\karaoke\testsort.py", line 11, in <module>
    root.sort(root._sortby) # user-defined order, in _sortby.fix list
  File "C:\Program Files (x86)\Python38-32\lib\site-packages\FATtools\FAT.py", line 1850, in sort
    names.sort(key=functools.cmp_to_key(by_func)) # user order
  File "C:\Program Files (x86)\Python38-32\lib\site-packages\FATtools\FAT.py", line 1818, in _sortby
    return cmp(Dirtable._sortby.fix.index(a), Dirtable._sortby.fix.index(b))
NameError: name 'cmp' is not defined

Can you let me know what is wrong here? Also, I was getting this same error with my own code, which is why I tried your sample. In my code I am trying to sort files, not directories in a certain order. Is there a difference for this, or can I just feed it the filenames as you have supplied DirA, DirB, DirC, etc... Also, I have these file names contained in a python list and reformatted them to a string with \n character to more closely fit with your sample. This resulted in the same errors as above, so I think there is more to it than my code. However, is there a way to feed it a list directly without having to parse it to a string with defined separator?

thanks.

bengalih commented 2 years ago

It appears cmp() is not supported in Python 3.x....

bengalih commented 2 years ago

Reverting from:

return cmp(Dirtable._sortby.fix.index(a), Dirtable._sortby.fix.index(b))

to:

            if Dirtable._sortby.fix.index(a) < Dirtable._sortby.fix.index(b):
                return -1
            elif Dirtable._sortby.fix.index(a) > Dirtable._sortby.fix.index(b):
                return 1
            else:
                return 0

fixed the issue.

It also appears to work with a list of filenames instead of directories as I asked. So, apart from fixing the code for Python 3.x compliance, my only remaining question is can I feed this a list directly or do I need a separated string? I could just .join the string with \n, but wanted to clarify.

thanks

maxpat78 commented 2 years ago

Last commit should finally fix and clarify the whole matter ('cmp' bug was a regression introduced by me with a recent code drop, sorry).

This is the basic sorting idea I want to implement:

import functools

# List to sort
L = ['Ta', 'Bu', 'Fr', 'bi', 'no', 'be', 'CU']
P = ['bi', 'be', 'Ta', 'Zu'] # parametric order: these items, if present, must come first

def _sortby(a, b):
   if a not in P: return 1
   if b not in P: return -1
   if P.index(a) < P.index(b): return -1
   if P.index(a) > P.index(b): return 1
   return 0

print('Original list:', L)
print('Sorted: alphabetical, case-insensitive', sorted(L, key=str.lower))
print('Sorted with %s on top:'%P, sorted(L, key=functools.cmp_to_key(_sortby)))

and this is working FATtools sample with Ram Disk:

# -*- coding: cp1252 -*-
# Sample mixed access with Python & FATtools
from FATtools.Volume import vopen, vclose
from FATtools.mkfat import exfat_mkfs, fat32_mkfs
from FATtools.disk import disk
import io

BIO = io.BytesIO((8<<20)*b'\x00')

# Reopen and format with EXFAT
o = vopen(BIO, 'r+b', what='disk')
print('Formatting...')
exfat_mkfs(o, o.size)
#~ fat32_mkfs(o, o.size)
vclose(o) # auto-close partition AND disk

# Reopen FS and play
print('Writing...')
o = vopen(BIO, 'r+b')

# Write some files with Python and sort them
T = ['Ta', 'Bu', 'Fr', 'bi', 'no', 'be', 'CU']
for t in T:
   f = o.create(t+'.txt')
   f.write(b'This is a sample "%s.txt" file.'%bytes(t,'ascii'))
   f.close()

o.sort()
print(o.listdir())

o._sortby.fix = ['bi.txt', 'be.txt', 'Ta.txt', 'Zu.txt'] # parametric order: these items, if present, must come first
o.sort(o._sortby)
print(o.listdir())

vclose(o)

open('BIO.IMG','wb').write(BIO.getbuffer())

As you can see reading such code (and inside FAT.py/exFAT.py Dirtable ._sort and .sort): 1) _sortby.fix MUST be a list of directory table (=file system) names; 2) such list can contain file or directory names, or both: they are recorded in a physical FAT/exFAT directory table the same way; 3) you can create such list the way you prefer - obviously, feeding a textual list made by hand and splitting lines is only a sample, but you can follow such an approach if you're eager to sort an USB stick without writing tons of code, like I often am; 4) such list can contain unknown names: and they will be ignored while sorting; 5) names not listed in .fix are left unchanged, in their original order