Skip to content

Resolve config and temp paths independently of the working directory - #93

Merged
kbrddestroyer merged 1 commit into
strodgers:mainfrom
dwaycik:fix/paths-relative-to-cwd
Aug 3, 2026
Merged

Resolve config and temp paths independently of the working directory#93
kbrddestroyer merged 1 commit into
strodgers:mainfrom
dwaycik:fix/paths-relative-to-cwd

Conversation

@dwaycik

@dwaycik dwaycik commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Three related paths in configs/constants.py resolve against the current working directory, so an installed copy only works when run from a source checkout.

1. PATH_TO_DEFAULT_CONFIG cannot be found after install

PATH_TO_DEFAULT_CONFIG = "src/epomakercontroller/configs/default.json"

That path only exists inside a checkout. From anywhere else:

$ cd ~ && python -c "from epomakercontroller.configs.configs import load_main_config; load_main_config()"
FileNotFoundError: [Errno 2] No such file or directory: 'src/epomakercontroller/configs/default.json'

This affects any desktop launcher or systemd service, where the working directory is the home directory. Now resolved against __file__, where the file is actually installed.

2. The config directory follows the working directory

def get_main_config_directory() -> Path:
    home_dir = Path(os.path.abspath(os.curdir))

The variable is named home_dir but holds os.curdir, so each working directory gets its own .epomaker-controller/. 0.0.8 used Path.home(); restored.

3. constants.py creates a directory at import time

TMP_FOLDER = os.path.abspath("./.epomaker_controller")
...
if not os.path.exists(TMP_FOLDER):
    os.mkdir(TMP_FOLDER)

Importing the package creates a directory in the caller's working directory. Moved under tempfile.gettempdir(), and created by generate_udev_rule() — the only thing that writes there — so behaviour is unchanged.

Found while building a GTK front end against 0.0.9; I currently patch these at import to make a systemd user service work.

@kbrddestroyer
kbrddestroyer self-requested a review August 2, 2026 08:39

@kbrddestroyer kbrddestroyer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As commented, I'd suggest storing configs inside project directory. Leave a comment if you have any other options


def get_main_config_directory() -> Path:
home_dir = Path(os.path.abspath(os.curdir))
home_dir = Path.home()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if we're working with home directory I'd rather pick .config/ folder. But as for me, the best way would be to resolve project install directory and work inside it.

Maybe something like Path(__file__).parent() would work here?

# Create temp folder in project path on Linux as well
if not os.path.exists(TMP_FOLDER):
os.mkdir(TMP_FOLDER)
# Created on demand by whatever writes there, rather than as an import side

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, but I think this comment is not necessary

Three paths in configs/constants.py resolve against the current working
directory, so an installed copy only works when run from a source checkout.

1. PATH_TO_DEFAULT_CONFIG was 'src/epomakercontroller/configs/default.json',
   a path that only exists inside a checkout. From anywhere else,
   load_main_config() raises FileNotFoundError -- which includes any desktop
   launcher or systemd service. Now resolved against __file__.

2. get_main_config_directory() used Path(os.path.abspath(os.curdir)), so each
   working directory got its own config. Where it writes is now selected by
   USE_XDG_CONFIG_DIR in constants.py: True (the default) uses
   $XDG_CONFIG_HOME, falling back to ~/.config; False keeps it alongside the
   installed package. The suite passes either way.

3. constants.py ran os.mkdir at import time, creating a directory in the
   caller's working directory as a side effect of importing the package. The
   folder moves under tempfile.gettempdir() and is created by
   generate_udev_rule(), the only code that writes there.

test_constants.py asserted the temp folder existed immediately after import,
which only held because of that import-time mkdir. It now checks that the
writable paths are absolute, that config lives outside the package when
USE_XDG_CONFIG_DIR is set, and that the bundled default config is readable.
@dwaycik
dwaycik force-pushed the fix/paths-relative-to-cwd branch from 554d96c to 010e2d9 Compare August 2, 2026 20:49
@dwaycik

dwaycik commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review, and for merging #92.

Switched to ~/.config as you suggested, and PATH_TO_DEFAULT_CONFIG now resolves against constants.py.

For the user config I've put it behind a switch so you can take either without another round-trip:

USE_XDG_CONFIG_DIR = True   # False -> alongside the installed package

Suite passes both ways. Defaulted to True since the package directory is usually root-owned on installs, replaced on upgrade, and shared between users — running the tests with False also drops a config.json into src/epomakercontroller/configs/. Flip it if you'd rather; happy to drop the flag once decided.

CI failure was test_constants.py asserting TMP_FOLDER exists right after import, which only held because of the import-time mkdir this removes.

@kbrddestroyer
kbrddestroyer self-requested a review August 3, 2026 03:37
@kbrddestroyer
kbrddestroyer merged commit 0d886bb into strodgers:main Aug 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants