# Open a file, by looking in an ordered list of directories (search path)

I have a small Python application that needs to load a few different files (templates and config files). It should look in a number of destinations, in the following order, and load the file from the first destination that contains such a file.

• current working directory
• $MYAPP_PATH (may contain several paths,separated by colon) • /usr/local/lib/python3.8/dist-packages/myapp/resources/ I have written the following: def open_sp(filepath): #open searchpath pathlist = [] pathlist.append('.') pathlist.extend(os.environ['MYAPP_PATH'].split(':')) pathlist.append(os.path.join(os.path.abspath(os.path.dirname(__file__)),'resources')) for p in pathlist: try: return open(os.path.join(p,filepath)) except FileNotFoundError: pass raise FileNotFoundError()  And I have exported the following environment variable in shell: $ export MYAPP_PATH=/home/jdoe/templates/:/home/jdoe/legacy_templates/


In my case, it will look for the file in the following locations:

• ./foo.conf
• /home/jdoe/templates/foo.conf
• /home/jdoe/legacy_templates/foo.conf
• /usr/local/lib/python3.8/dist-packages/foo.conf

And it seems to work. But I suspect this could be much more elegant, perhaps by using some built-in Python tool, maybe from the importlib-package.

Also, if considering my code, I'm not sure if FileNotFound is the proper exception to throw, since it expects a path argument, and I am not sure which of the path arguments to provide.

• A colon ':' can be a valid character in a Windows path. It might make your code more portable to use a semi-colon ';' to separate paths in MYAPP_PATH. Jun 17 at 0:49
• @RootTwo: Good point. However I believe the convention on Unix is to use colons as separator, and I simply chose to stick to this convention. Jun 19 at 19:05

Rather than incrementally building up a list, you can just use a tuple literal.

Prefer pathlib over os.path for path manipulation.

This function shouldn't be obligated with opening the file, only finding the first matching path.

Raising FileNotFoundError is fine but you should give it a sane error message string.

## Suggested

import os
from pathlib import Path

def get_path(filename: str) -> Path:
paths = (
'.',
*os.environ['MYAPP_PATH'].split(':'),
Path(__file__).parent / 'resources',
)
for p in paths:
path = Path(p) / filename
if path.is_file():
return path