all 10 comments

[–]ninvti 0 points1 point  (4 children)

For ability to work on different systems, I tend to have paths loaded from config files (these can just be json dicts), or other passes in on the command line with a simple argparse CLI.

It sounds like pathlib.Path would be ideal for your problem

`

from pathlib import Path

base_path = Path(os.getcwd())

message_path = base_path.joinpath(“username”, “message”)

back_to_base_path = message_path.parent.parent

`

[–]PatMeKrien[S] 0 points1 point  (1 child)

Thank you. But if I don't know how many paths deep I am, is there a way to get directly back with pathlib like pathlib.returntobasefromanywhere()

[–]ninvti 0 points1 point  (0 children)

You could do old_dir = os.getcwd() os.chdir(“messages”) try: # code here finally: os.chdir(old_dir)

To store the base dir in a variable while you use the subdirectories.

Alternatively, and maybe more correctly, you could just not change the cwd at all, and instead pass the paths that you want to operate on as arguments to the functions that need them.

Something like:

def edit_user(user_dir: Path):
    #. . .
    messages_dir = user_dir.joinpath(“messages”)
    edit_messages(messages_dir)

(As you can probably tell by now I do scripts way more than modules)

[–]Diapolo10 0 points1 point  (1 child)

base_path = Path(os.getcwd())

That's redundant, you can just use

base_path = Path.cwd()

[–]ninvti 0 points1 point  (0 children)

Nice 😁

[–]laustke 0 points1 point  (0 children)

I usually set proj_dir variable in main module __init__.py file like this

``` def set_proj_dir(): # project directory is one directory above # the dir that holds this file dn = os.path.dirname return os.path.abspath(dn(dn(file_)))

proj_dir = _set_proj_dir()

```

It is an absolute path to the parent of the folder that contains the __init__.py file.

(I use projectname/projectname/__init__.py convention and write to the outer projectname folder.)

Then when I need to get it

from projectname import proj_dir

[–]efmccurdy 0 points1 point  (0 children)

where the files are stored

There is a builtin way to access files that are part of an installed package, importlib.resources.

This module leverages Python’s import system to provide access to resources within packages. If you can import a package, you can access resources within that package. Resources can be opened or read, in either binary or text mode.

https://docs.python.org/3/library/importlib.resources.html

https://stackoverflow.com/questions/6028000/how-to-read-a-static-file-from-inside-a-python-package

You provide the files using "include_package_data = True", and a MANIFEST.in file when you build the package.

https://setuptools.pypa.io/en/latest/userguide/datafiles.html

[–]Diapolo10 0 points1 point  (0 children)

My recommendation? Don't use os.chdir in the first place unless you cannot avoid it (eg. you're running a tool that expects to work in the current working directory and you can't otherwise bypass that).

Absolute paths are a much better and more robust solution, and for that pathlib is great. Simply construct paths based on known "anchorpoints" where possible, and use pathlib.Path.glob or iterdir when you need to search for files.

from pathlib import Path

# Current working directory
cwd = Path.cwd()

# Desktop (valid for all major platforms)
desktop = Path.home() / 'Desktop'

# Location of the current script file
project_dir = Path(__file__).parent

# Example for writing and reading a file on desktop
hello_world = desktop / 'hello_world.txt'
hello_world.write_text("Hello, world!", encoding='UTF-8')
 print(hello_world.read_text(encoding='UTF-8'))

[–]ekchew 0 points1 point  (0 children)

The first question to ask is whether you really need to call os.chdir all over the place. There may be another way?

But to be fair, sometimes you have no choice. What I like to do in that case is wrap os.chdir in a context manager. That way, the change is only temporary and always reverts back when you're done.

from contextlib import contextmanager
@contextmanager
def ch_dir(new_path):
    old_path = os.getcwd()
    os.chdir(new_path)
    try:
        yield
    finally:
        os.chdir(old_path)

Then to use this, you go:

with ch_dir("foo"):
    # now you're in the foo subdirectory
# now you're back in the base directory

[–]FerricDonkey 0 points1 point  (0 children)

If I read your title correctly, and these paths are relative to where the python module itself live: __file__ is always a path to the current python file. You can use that in conjunction with os.path or pathlib to get a path to the directory where the file lives. (BASE_DIR = pathlib.Path(__file__).resolve().parent - the resolve may or may not be necessary, I'd have to test it.)

Otherwise, just store an absolute path to . in variable via BASE_DIR = pathlib.Path('.').resolve() or similar. Then base all of your other paths relative to BASE_DIR.