Link to home
Start Free TrialLog in
Avatar of Isaiah Melendez
Isaiah Melendez

asked on

How To Loop - Python

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

Avatar of aikimark
aikimark
Flag of United States of America image

os.listdir() will give you an iterable list of files in a directory.
the glob library does facilitate filtering the list of files with a wildcard pattern.

reference: https://docs.python.org/2/library/glob.html
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.
Avatar of Isaiah Melendez
Isaiah Melendez

ASKER

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...
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

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

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

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
so @pepr what do you recommend I do?
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)
@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

@Sj77

Have you tested my code?
@aikimark

Yes, got invalid synthax error at <>0:

The highlighting was on the > sign.
That feedback would have been helpful three days ago :-(
Then try this inequality check syntax.
        if len(m)!=0:

Open in new window

both run fine in Python 2.7
My apologies. I thought I had replied and clearly I did not. I am using v 3.5.2
ASKER CERTIFIED SOLUTION
Avatar of pepr
pepr

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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

WOW, again, @pepr you do not fail!

Thank you, this worked!