0

This is difficult to summarize what I am trying to do, I doubt the Title made it any easier to follow but...

I am using tkinter to build an options dialog box, allowing the user to enter their own file name breakdown structure. Os.Walk would read and setup the folder structure based on the users input.

Config Parser/User Input

[Alpha] aoth = file[:1], file[:3]

The issue is that I can breakdown the structure based on user input (I.E Read 'aoth' in Alpha structure, break down by two folders). However Os.Walk/Python considers this as the actual input. Broke down the code to only show the relevant information:

for root, subFolders, files in os.walk(Entry.get(self.sourceE)):
    for file in files:
        if not file.startswith('.'):
            if file[0].isalpha():
                alpfol = '%s' % self.alpha_fol.get()
                alset = self.alphaa_radio.get()
                if alset == 1:
                    file_strut = '%s' % file[:1]
                elif alset == 2:
                    file_strut = '%s/%s' % (file[:1], file[:2])
                elif alset == 3:
                    files_strip = [st.strip() for st in (self.radio_aBoxV.get()).split(',')]
                    files_count = len(files_strip)
                    ###
                    file_count_check = '%s/'*files_count
                    file_strut = file_count_check % tuple(files_strip)
                    ###
                subFolder = os.path.join(Entry.get(self.destE), alpfol, file_strut)
            checkFile = os.path.join(subFolder, file)
                ........

I know it's not the most elegant code, but alset 1/2 work flawlessly whereas alset 3 considers file[:1]/file[:3] as literal input. How would I make the users input read the actual file name and break down accordingly? I'm sure its something very simple I'm missing.

Thanks for reading this!

sdavis891
  • 101
  • 1
  • 3
  • 10
  • what is a "filename breakdown structure"? – Bryan Oakley Jun 20 '16 at 12:16
  • Also, this is strange: `Entry.get(self.sourceE)` -- why aren't you calling `self.sourceE.get()`? – Bryan Oakley Jun 20 '16 at 12:17
  • Let me elaborate. A user wants to move files from a source folder to a destination folder. Using an options dialog, he chooses between three options. Option A sorts by the First Letter of the file name (A/Alpha.tiff), Option B sorts by First and then the next two (C/CH/Chicken.jpg), and finally Option C allows the user to input their own. I cannot get Option C's self.radio_aBoxV.get() to treat the input like it's the actual file variable. – sdavis891 Jun 20 '16 at 12:46
  • Yes it is, I haven't gotten around to fixing that part yet :) But that hasn't been an issue yet. – sdavis891 Jun 20 '16 at 12:47
  • This statement makes no sense: _"I cannot get Option C's self.radio_aBoxV.get() to treat the input "_ - a radiobutton doesn't "treat the input". It holds a value and nothing more. Are you saying it's returning the wrong value? What is `self.radio_aBoxV.get()` returning? – Bryan Oakley Jun 20 '16 at 12:53
  • self.alphaa_radio is the radio button, self.radio_aBoxV is returning "file[:1], file[:3]" from the configuration file. So a user selects an "other" radio button (self.alphaa_radio) which has a value of three... If alset==3 then get the associated Entry box. Does that make sense now? – sdavis891 Jun 20 '16 at 13:33

1 Answers1

0

Well, like you suggested it's a pretty simple and obvious error:

"file[:1],file[:2]" is not the same as file[:1],file[:2].

Your first two options are hardcoded, so they're taking the reference file and applying slice notation to it. The last one takes a String and just throws it around; the program has no idea that you mean for it to convert the String "file" to the Reference file and the String "[:1]" and convert it to slice notation [:1].

The solution to the problem is to make that conversion, probably by going into the String and pulling the necessary information out of it. You do this to get the number of partitions, but never convert the reference and slice notation. You could take those partitions you have in your code and do some finangling using split or slice notations to "cut" the important bits out, but I'm going to suggest Regex (re module in Python) as it's a more flexible solution.

Python RE HowTo

Below is a sample that I have mostly working; I have a comment at the one point that may cause it to give imperfect results (both negative start and step at same time), but it's a really obscure case and you can get the code up to 100% just by removing the option to use the step portion of slice notation. You'll also note that simply taking slice notations blindly from the user can lead to malformed directory names.

(Note- I don't actually program in Python 2, but as far as I know this is 2.7 safe; hopefully only necessary changes are minor syntax adjustments)

import os, os.path
import re

PATTERNRE=re.compile('''(?P<parts>[Ff]ile\[(?P<start>-?\d*):+(?P<end>-?\d*):?(?P<step>-?\d*)\])''')

def formatindices(start,end,step,file): ## Slice Notation only accepts Ints,
                                        ## and int('{empty string}') raises an error,
                                        ## so we're programming around it
    step = int(step) if step else 1
    if not start:
        if step>0: start=0
        else: start=-1
    else:
        start=int(start)
    end = int(end) if end else len(file) ## Having both negative Start and Step will
                                         ## break this on the else statement, couldn't
                                         ## find an integer to represent "index before 0"
    return start,end,step

files=['hello.py','world.pyc','helloworld.tar.gz.','foo.pyo','bar.pyo','foobar.whl']
patterns=['fl<;>','file[:]','file[:1],file[:2]','file[1:2]','file[:2],file[2:4]','file[:-3:2],file[:-2:-1],file[-1:]']

for i,(file,pattern) in enumerate(zip(files,patterns),start=1):
    try:
        if not file.startswith('.') and file[0].isalpha():
            print "Trial %d: %s=>%s" % (i,file,pattern)

            matches=PATTERNRE.finditer(pattern) ## Use Re to find all "file[x:y:z]"
            ## Convert to  list of tuples
            indices=[(match.group('start'),match.group('end'),match.group('step')) for match in matches]
            ## Using IOError because a lot that can otherwise go wrong comes up as
            ## ValueError (Which is the most-logical ErrorName)
            if not indices: raise IOError('Bad Formatting')

            ## Standardize indexes
            indices=[formatindices(start,end,step,file) for start,end,step in indices]
            print 'Indices: '+'|'.join(','.join(str(item) for item in startendstep) for startendstep in indices)

            ## Build File Structure
            file_strut='\\'.join(file[start:end:step] for start,end,step in indices)
            print 'Folder Structure: '+file_strut

            ## Put together
            subFolder = os.path.join('directoryfrom self.destE', 'somefolder alpfol', file_strut)
            print'Output: '+subFolder+'\n'
    except IOError:
        print 'No Pattern, Skipping\n'
Reid Ballard
  • 1,480
  • 14
  • 19
  • Giving my code one more look, you could also use a logic tree to determine how to write the slice notation based on what `re` pulls out of the String; i.e.- `if start: if end and step: index[start:end:step];elif end: file[start:end] _etc_`. This is certainly viable and gets around the one bad case, but this seems a lot more streamlined and easy to work around. – Reid Ballard Jun 21 '16 at 19:54