0

I am trying to use my code to open a file after searching for it in either operating system. However when I assign the variable inside the function, i cant use it outside of the function. And when I keep the 2nd function out of 1st function, it doesnt recognize the function.

I tried to assign the df_location globally, but this doesnt work. When i use df = pd.read_csv(df_location[0], index_col=0) inside the function, I am not able to use df anywhere else in my code.

if platform.system() == 'windows':
    def find_file(root_folder, rex):
        for root, dirs, files in os.walk(root_folder):
            for f in files:
                result = rex.search(f)
                if result:
                    file_path = os.path.join(root, f)
                    return file_path  

    def find_file_in_all_drives(file_name):

        matching_files = list()
        # create a regular expression for the file
        rex = re.compile(file_name)
        for drive in win32api.GetLogicalDriveStrings().split('\000')[:-1]:
            file_path = find_file(drive, rex)
            if file_path:
                matching_files.append(file_path)
        return matching_files

    global df_location
    df_location = find_file_in_all_drives("AB_NYC_2019.csv")

if platform.system() == 'mac':
    df_location = find_file("/", "AB_NYC_2019.csv")


df = pd.read_csv(df_location[0], index_col=0)

I would like to be able to use the file that is retrieved through the functions.

Thank you!

ideally it should be like this

if platform.system() == 'windows':
    def find_file(root_folder, rex):
        for root, dirs, files in os.walk(root_folder):
            for f in files:
                result = rex.search(f)
                if result:
                    file_path = os.path.join(root, f)
        return file_path  

    def find_file_in_all_drives(file_name):

        matching_files = list()
        # create a regular expression for the file
        rex = re.compile(file_name)
        for drive in win32api.GetLogicalDriveStrings().split('\000')[:-1]:
            file_path = find_file(drive, rex)
            if file_path:
                matching_files.append(file_path)
        return matching_files

df_location = find_file_in_all_drives("AB_NYC_2019.csv")

if platform.system() == 'mac':
    df_location = find_file("/", "AB_NYC_2019.csv")


df = pd.read_csv(df_location[0], index_col=0)

but this gives the error message: "NameError: name 'find_file_in_all_drives' is not defined"

7
  • I don't understand the issue. You appear to have diagnosed the problem exactly; what are you struggling with from your research around this common problem? Commented Oct 15, 2019 at 19:13
  • When I assign it globally, it still says the variable is undefined. When I place df_location = find_file_in_all_drives("AB_NYC_2019.csv") outside of the function, it doesnt recognize the function. Sorry i am very new and struggling a lot. Commented Oct 15, 2019 at 19:16
  • 2
    You never once define df_location inside a function. So I have no idea what you are referring to. Commented Oct 15, 2019 at 19:17
  • It seems you are doing global df_location in the global scope, which will do nothing. In any case, it looks like the problem is that your functions are defined in an if block, so if the condition isn't true, they won't be defined. It's hard to say. But think about what happens if platform.system() == 'mac': is true, then none of the variables you are using will be defined. It would help if you post the full error messages Commented Oct 15, 2019 at 19:19
  • 1
    It looks to me that the problem isn't the global, it's the fact that find_file is defined inside an if block so if your system is mac it tries to call find_file but it's never been defined. Commented Oct 15, 2019 at 19:19

2 Answers 2

1

You define find_file_in_all_drives for Window but you should define find_file_in_all_drives also for other systems - but every system will have different code in find_file_in_all_drives. And then you can use find_file_in_all_drives on every system

# all systems use it so it should be defined for all

def find_file(root_folder, rex):
    for root, dirs, files in os.walk(root_folder):
        for f in files:
            result = rex.search(f)
            if result:
                file_path = os.path.join(root, f)
    return file_path  

# define different `find_file_in_all_drives` for different systems     

if platform.system() == 'windows':

    def find_file_in_all_drives(file_name):
        matching_files = list()
        # create a regular expression for the file
        rex = re.compile(file_name)
        for drive in win32api.GetLogicalDriveStrings().split('\000')[:-1]:
            file_path = find_file(drive, rex)
            if file_path:
                matching_files.append(file_path)
        return matching_files

if platform.system() in ('mac', 'linux'):

    def find_file_in_all_drives(file_name):
        return find_file("/", file_name)

# now you can use `find_file_in_all_drives` on every system

df_location = find_file_in_all_drives("AB_NYC_2019.csv")

df = pd.read_csv(df_location[0], index_col=0)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer furas! As you explained, seperated the find_file from the if statements. I first tried to copy your code entirely but then it gave the error that find_file_in_all_drives is assigned twice. So i change the mac/ linux version to ``` if platform.system() == 'Mac': df_location = find_file("/", "AB_NYC_2019.csv") ``` The code now runs and works, on windows atleast. I cannot test it on mac as of right now, but I hope the mac /linux part is also correct. Thank you again for your help!
1

You didn't show all your code. Presumably, you have find_file and find_file_in_all_drives function implementations for mac as well, yes? At least that's what I would expect just from looking at the code you've posted.

If that really is ALL the code you have, then the way it's written now, you're only defining find_file and find_file_in_all_drives if platform.system() returns "windows" (side note: just tried this, on my Windows 7 system it returns "Windows" with a capital 'W'.) If that condition is not satisfied these function definitions are not visible anywhere else in your code, because you've put them inside the body of the if-statement.

It looks like you are trying to get different behavior depending on the contents of a string (platform.system()). Since you can't avoid having to implement the varying behavior for both operating systems, you can use polymorphism for this:

import abc


class DataFrameFinder(abc.ABC):

    def __init__(self):
        pass

    @abc.abstractmethod
    def find_file(self, root_folder, rex):
        raise NotImplementedError

    @abc.abstractmethod
    def find_file_in_all_drives(self, file_name):
        raise NotImplementedError


class DataFrameFinderWindows(DataFrameFinder):

    def __init__(self, *args, **kwargs):
        DataFrameFinder.__init__(self, *args, **kwargs)

    def find_file(self, root_folder, rex):
        # Do windows things...
        pass

    def find_file_in_all_drives(self, file_name):
        # Do windows things...
        pass


class DataFrameFinderMac(DataFrameFinder):

    def __init__(self, *args, **kwargs):
        DataFrameFinder.__init__(self, *args, **kwargs)

    def find_file(self, root_folder, rex):
        # Do mac things...
        pass

    def find_file_in_all_drives(self, file_name):
        # Do mac things...
        pass

def main():

    import platform

    finder_factory = {
        "Windows": DataFrameFinderWindows,
        "Mac": DataFrameFinderMac
    }

    finder = finder_factory[platform.system()]()

    finder.find_file(...)

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

5 Comments

return 0 ... sys.exit(main()) Python != C . Also, note your class definitions are incorrect (missing self in the instance methods) ... not really sure why you need these classes to begin with...
I suppose it's a matter of taste. Personally I think this is cleaner and it's more explicit, which is desirable. Didn't catch the missing selfs though. Thanks. You don't NEED these classes, I'm just offering alternatives. What I was sayign is that If the OP really does need different implementations of these functions depending on the operating system, they might as well wrap them in classes and use polymorphism. The alternative would be a dictionary or some if-statements, but they wouldn't be saving many lines of code doing it that way.
Thank you for taking the time to answer my question. Your code is too advanced for me to understand, and since I have to be able to understand it and explain it (its for my study), I went with the alterations that furas made. Thank u tho!
Sure, my point is mainly that the OP is struggling to understand why the variables aren't defined, so throwing out a class hierarchy with an abstract base class may not be the most helpful thing, pedagogically. In any case, though, note you are using a dictionary.
Sorry for not being clear. What I meant was that alternatively they would have to define four functions (two for each operating system), and then, using a dictionary, map the two OS-strings to the associated functions in some way. I didn't mean to suggest that I wasn't using a dictionary. What you're saying is totally fair though. If certain feedback is too advanced for the OP, or the features are too foreign, it has little value.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.