?
Solved

How To Loop - Python

Posted on 2016-10-03
19
Medium Priority
?
133 Views
Last Modified: 2016-10-07
Hello Experts -

I am familiar with looping in programming in general but I am a novice in python. I am trying to get my code to loop through a directory of MDBs and basically do compact and repair. I have the working code that does work for one file but I need it do it repeatedly for every file in the given directory.

The given directory would be a network path: \\fp1\rowp

import subprocess
import os

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])

if __name__ == '__main__':    
    mdb_repair('C:\\Test\\AR001.mdb')

Open in new window

0
Comment
Question by:sj77
  • 7
  • 7
  • 3
  • +1
19 Comments
 
LVL 46

Expert Comment

by:aikimark
ID: 41827178
os.listdir() will give you an iterable list of files in a directory.
0
 
LVL 46

Expert Comment

by:aikimark
ID: 41827180
the glob library does facilitate filtering the list of files with a wildcard pattern.

reference: https://docs.python.org/2/library/glob.html
0
 
LVL 46

Expert Comment

by:aikimark
ID: 41827186
The subprocess library has a check_output() function that may be more efficient if you have a lot of files in the folder and want the OS's file system to do the filtering.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:sj77
ID: 41827189
Logically though is where I am stuck. I am not a strong programmer, so, I would not know which loop condition to use and how to structure it. Some guidance would help...
0
 
LVL 46

Expert Comment

by:aikimark
ID: 41827210
Please test this:
mdbs=subprocess.check_output("dir /b C:\Test\*.mdb",shell=True)
for m in mdbs.split("\r\n"):
    if len(m) <>0:
        mdb_repair('C:\\Test\\' + m)

Open in new window

0
 
LVL 1

Expert Comment

by:ltpitt
ID: 41827587
What about this (needs testing):

import subprocess
import os

folder_path = "c:/your/mdb/path"

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])


if __name__ == '__main__':
    for file in os.listdir(folder_path):
        filename, file_extension = os.path.splitext(file)
        if file_extension.lower() == '.mdb':
            mdb_repair(file)

Open in new window

0
 
LVL 29

Expert Comment

by:pepr
ID: 41828837
Here is the code that calls the print instead of your function to show how to do it. I have tried the faked .mdb files. Notice that one of them has the .MDB extension (capital letters). Read the comments and see the output below the code:
#!python3

import glob
import os

print('------ glob')
# The glob.glob() is probably the easiest to use here. Notice that it
# finds also the files with the extension .MDB (that is capital letters).
lst = glob.glob('d:/__Python/sj77/ee28974050/*.mdb')
for fname in lst:
    print(fname)

print('------ bare name by listdir()')
# The os.listdir() return only the list of bare names.
lst = os.listdir('d:/__Python/sj77/ee28974050')
for fname in lst:
    print(fname)

# It is always good to assign things like a path to a variable.
# You may usually guess, but once you type it more than once, it should
# be clear. Moreover, later you may wrap the code as a function body,
# and the variable will become its argument (that is no need to rewrite
# the function body).
directory = 'd:/__Python/sj77/ee28974050'

print('------ listdir result joined with the directory')
# You can use the os.path.join() to join the directory with the bare name.
# However, notice that the earlier glob.glob() is probably easier to read.
lst = os.listdir(directory)
for fname in lst:
    print(os.path.join(directory, fname))

print('------ listdir result joined with the directory')
# If it is simple enough, no need for the extra variable (here lst).
for fname in os.listdir(directory):
    print(os.path.join(directory, fname))

print('------ normalized')
# Sometimes the extra variable is better to introduce (here fullname).
# In Windows, users are used to see backslashes instead of slashes.
# You can normalize the path (if you need some uniform output; anyway,
# it is better to use normal slashes in your code). Anyway, the name casing
# is not changed (here the .MDB with capital letters).
for fname in os.listdir(directory):
    fullname = os.path.normpath(os.path.join(directory, fname))
    print(fullname)

print('------ the alternative testing for the .mdb extension')
# As ltpitt has shown, splitting the extension is often used.
# Sometimes, it may be easier to read when you just test with .endswith()
# string methods. However, you still need to convert to .lower()
for fname in os.listdir(directory):
    fullname = os.path.normpath(os.path.join(directory, fname))
    if fullname.lower().endswith('.mdb'):
        print(fullname)

print('------ glob.iglob() as two lines')
# The glob.glob() returns the list of strings, and then the list is
# often iterated using the for loop. There is also the .iglob() variant
# that does not save the path to the list first. Instead, it returns
# the file names one by one. Notice, that you can still use the directory
# variable and the os.path.join() (or possibly even the .normpath() to build
# the mask for the glob. (The glob functionality and the name came from UNIX.)
for fname in glob.iglob(os.path.join(directory, '*.mdb')):
    print(fname)

# For me, the last one is the shortest, easiest to read, less error prone,
# and efficient (or with the full path, or with os.path.join() -- it depends
# on situation.
#
# Call your function instead of the print().

Open in new window

The output in my case was:
d:\__Python\sj77\ee28974050>py a.py
------ glob
d:/__Python/sj77/ee28974050\a.mdb
d:/__Python/sj77/ee28974050\b.mdb
d:/__Python/sj77/ee28974050\c.MDB
------ bare name by listdir()
a.mdb
a.py
b.mdb
c.MDB
------ listdir result joined with the directory
d:/__Python/sj77/ee28974050\a.mdb
d:/__Python/sj77/ee28974050\a.py
d:/__Python/sj77/ee28974050\b.mdb
d:/__Python/sj77/ee28974050\c.MDB
------ listdir result joined with the directory
d:/__Python/sj77/ee28974050\a.mdb
d:/__Python/sj77/ee28974050\a.py
d:/__Python/sj77/ee28974050\b.mdb
d:/__Python/sj77/ee28974050\c.MDB
------ normalized
d:\__Python\sj77\ee28974050\a.mdb
d:\__Python\sj77\ee28974050\a.py
d:\__Python\sj77\ee28974050\b.mdb
d:\__Python\sj77\ee28974050\c.MDB
------ the alternative testing for the .mdb extension
d:\__Python\sj77\ee28974050\a.mdb
d:\__Python\sj77\ee28974050\b.mdb
d:\__Python\sj77\ee28974050\c.MDB
------ glob.iglob() as two lines
d:/__Python/sj77/ee28974050\a.mdb
d:/__Python/sj77/ee28974050\b.mdb
d:/__Python/sj77/ee28974050\c.MDB

Open in new window

1
 

Author Comment

by:sj77
ID: 41832175
Hi @Itpitt-

Thank you for that. It works but I get the below error.

Here is my code:
import subprocess
import os

folder_path = ('C:\\Test\\')

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])


if __name__ == '__main__':
    for file in os.listdir(folder_path):
        filename, file_extension = os.path.splitext(file)
        if file_extension.lower() == '.mdb':
            mdb_repair(file)

Open in new window

error2python.jpg
0
 

Author Comment

by:sj77
ID: 41832181
so @pepr what do you recommend I do?
0
 
LVL 1

Expert Comment

by:ltpitt
ID: 41832255
My bad!

Add this row:

if __name__ == '__main__':
    os.cwd(folder_path)
    for file in os.listdir(folder_path):
        filename, file_extension = os.path.splitext(file)
        if file_extension.lower() == '.mdb':
            mdb_repair(file)
0
 

Author Comment

by:sj77
ID: 41832340
@Itpitt -

Thank you!

I did and got the following error:

========= RESTART: C:\Users\imelendez\Desktop\python\CNR_AllFiles.py =========
Traceback (most recent call last):
  File "C:\Users\imelendez\Desktop\python\CNR_AllFiles.py", line 22, in <module>
    os.cwd(folder_path)
AttributeError: module 'os' has no attribute 'cwd'

Open in new window


current code:
import subprocess
import os

folder_path = ('C:\\Test\\')

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])


if __name__ == '__main__':
    os.cwd(folder_path)
    for file in os.listdir(folder_path):
        filename, file_extension = os.path.splitext(file)
        if file_extension.lower() == '.mdb':
            mdb_repair(file)

Open in new window

0
 
LVL 46

Expert Comment

by:aikimark
ID: 41832429
@Sj77

Have you tested my code?
0
 

Author Comment

by:sj77
ID: 41832480
@aikimark

Yes, got invalid synthax error at <>0:

The highlighting was on the > sign.
0
 
LVL 46

Expert Comment

by:aikimark
ID: 41832504
That feedback would have been helpful three days ago :-(
0
 
LVL 46

Expert Comment

by:aikimark
ID: 41832510
Then try this inequality check syntax.
        if len(m)!=0:

Open in new window

both run fine in Python 2.7
1
 

Author Comment

by:sj77
ID: 41832611
My apologies. I thought I had replied and clearly I did not. I am using v 3.5.2
0
 
LVL 29

Accepted Solution

by:
pepr earned 2000 total points
ID: 41832682
I suggest to write another tiny function for repairing all .mdb files in the directory that is passed as its argument. Try this, and then uncomment the ##result = subprocess... line and the ##return line:
#!python3

import glob
import os
import subprocess

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    mdb_path = os.path.normpath(mdb_path)   # let's make the print more tidy
    print('Repairing', mdb_path, '...', end=' ')
    ##result = subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])
    print('done')
    ##return result

    
def repair_all_mdbs_in_folder(folder_path):
   """Finds all .mdb files in the folder_path and calls the repair function for them."""
   for fname in glob.iglob(os.path.join(folder_path, '*.mdb')):
       mdb_repair(fname)
       # Possibly also capture and process the output of the function if you need.
    

if __name__ == '__main__':
    repair_all_mdbs_in_folder('c:/Test/')

Open in new window

1
 
LVL 1

Expert Comment

by:ltpitt
ID: 41833158
Hi again...

I completed a few versions with slightly different use scenario.

This one is the 1st one I've sent you, now with bug fixed:
import subprocess
import os

folder_path = ('C:\\Test\\')

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])


if __name__ == '__main__':
    os.chdir(folder_path)
    for file in os.listdir(folder_path):
        filename, file_extension = os.path.splitext(file)
        if file_extension.lower() == '.mdb':
            mdb_repair(file)

Open in new window



This other one takes, as input from user, the path you that the user wants to fix.
Basically when the script is running, the user will be prompted to use the keyboard to input the path.

# Importing used libraries to handle files / folders / etc
import subprocess
import os

# This function is used to get the mdb path as input from user
def get_path_from_user():
# Prints an empty row to show what the script is doing with more clarity
    print()
# Asks the user which is the path and saves it in input_path variable
    input_path = raw_input("Please enter your path (example: c:/my/folder/): ")
# Checks if path written from user exists
    if os.path.exists(input_path):
# If path exists switches folder to the path folder
        os.chdir(input_path)
# For every file available in the folder
        for file in os.listdir(folder_path):
# Divide file name from file extension
            filename, file_extension = os.path.splitext(file)
# If file extension is ".mdb"
            if file_extension.lower() == '.mdb':
# Call function mdb_repair on that file
                mdb_repair(file)
    else:
# Since path could not be found let's print an error to the user
        print "\n*** Folder does not exist! ***"

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    print "Repairing files..."
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])

if __name__ == '__main__':
    get_path_from_user()

Open in new window



The last version is maybe more flexible because it allows you to specify the path as a parameter when running the script from command line.

Example:
python your_script_name.py c:/your/mdb/folder/

Here you can find it:
# Importing used libraries to handle files / folders / etc
import subprocess
import os
import sys

# This function is used to get the mdb path as input from user
def check_if_path_exists(input_path):
    print sys.argv[1]
# Prints an empty row to show what the script is doing with more clarity
    print()
# Checks if path written from user exists
    if os.path.exists(input_path):
# If path exists switches folder to the path folder
        os.chdir(input_path)
# For every file available in the folder
        for file in os.listdir(folder_path):
# Divide file name from file extension
            filename, file_extension = os.path.splitext(file)
# If file extension is ".mdb"
            if file_extension.lower() == '.mdb':
# Call function mdb_repair on that file
                mdb_repair(file)
    else:
# Since path could not be found let's print an error to the user
        print "\n*** Folder does not exist! ***"

def mdb_repair(mdb_path, msaccess='C:/Program Files/Microsoft Office/Office15/msaccess.exe'):
    """Repairs the mdb_path database using the msaccess utility."""
    print "Repairing files..."
    return subprocess.check_output([msaccess, '/compact', '/repair', mdb_path])

if __name__ == '__main__':
# Verify if user specified a path when the script was run
    if len(sys.argv) > 1:
# If so put this data into the variable input_path
        input_path = sys.argv[1]
# And run the get_path_from_user function
        check_if_path_exists(input_path)
    else:
        print "\n*** Please specify a path! ***"

Open in new window

1
 

Author Closing Comment

by:sj77
ID: 41834187
WOW, again, @pepr you do not fail!

Thank you, this worked!
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Swadhin
Introduction of Lists in Python: There are six built-in types of sequences. Lists and tuples are the most common one. In this article we will see how to use Lists in python and how we can utilize it while doing our own program. In general we can al…
This article will show, step by step, how to integrate R code into a R Sweave document
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
Suggested Courses
Course of the Month17 days, 9 hours left to enroll

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question