Skip to content

fix: accept app arguments in user_preference_dir - #531

Merged
gaborbernat merged 3 commits into
tox-dev:mainfrom
dylanpulver:fix/user-preference-dir-app-args
Aug 27, 2026
Merged

gaborbernat merged 3 commits into
tox-dev:mainfrom
dylanpulver:fix/user-preference-dir-app-args

Conversation

@dylanpulver

Copy link
Copy Markdown
Contributor

Differential check of the 54 module-level *_dir / *_path functions against the PlatformDirs properties they wrap: 0 value divergences in 12,960 comparisons, and 8 reach gaps. All 8 are user_preference_dir and user_preference_path.

Neither takes arguments, so neither can pass the app name or the version that the property acts on:

>>> platformdirs.user_preference_dir()
'/Users/me/Library/Preferences'
>>> platformdirs.PlatformDirs("MyApp", version="1.0").user_preference_dir
'/Users/me/Library/Preferences/MyApp/1.0'
>>> platformdirs.user_preference_dir("MyApp", version="1.0")
TypeError: user_preference_dir() takes 0 positional arguments but 2 were given

macOS appends the app name and version to ~/Library/Preferences. On the other three platforms user_preference_dir resolves to user_config_dir, which is app scoped as well. Either way the function can only return the unscoped base directory.

#491 added these two in one batch with app independent helpers such as user_fonts_dir, and the zero argument shape carried over to the one member of the batch it does not suit.

This gives both the signature of user_config_dir. Defaults are unchanged, so a no-argument call returns what it returns today.

The test asserts the invariant over every getter in PROPS: where the property varies with appname and version, the function must accept them. Reverting __init__.py fails it for user_preference_dir alone; the other 26 parametrizations pass either way, as pins.

Testing: full suite on macOS with 3.14, 1032 passed. The four test_compatibility[site_data_dir-*] failures reproduce on a clean origin/main worktree. Pinned ruff v0.16.4 is clean. Windows and Linux legs unrun here.

Drafted with Claude Code (Claude Opus 5). Not yet reviewed by a human; @dylanpulver will review before this is treated as ready.

dylanpulver and others added 2 commits August 27, 2026 13:12
user_preference_dir() and user_preference_path() took no arguments, so
they always returned the unscoped base directory. The property they wrap
is app scoped on every platform: macOS appends the app name and version
to ~/Library/Preferences, and Unix, Windows and Android resolve it to
user_config_dir.

PR tox-dev#491 added these two helpers in the same batch as user_publicshare_dir,
user_templates_dir and user_fonts_dir, which are app independent, and the
zero argument shape carried over to the one member of the batch that is
not.

Give both functions the signature of user_config_dir, the property they
resolve to on three of the four platforms. The defaults are unchanged, so
calling either with no arguments returns what it returns today.

The new test asserts the general invariant over every directory getter:
when the property varies with appname and version, the module level
function has to accept them. It fails only for user_preference_dir before
this change.
The original conditional asserted nothing for the 26 properties that do
not vary with the app name, and where it did fire it only checked that
appname and version appear in the signature, not that the function passes
them on. A wrapper accepting both and calling PlatformDirs() anyway still
passed.

Assert the implication with both branches carrying a claim: a function
taking the app arguments must return what the scoped property returns,
and one that does not must wrap a property that never varies. Only one
direction holds, since tox-dev#534 gives the applications functions arguments
that three of the four platforms ignore. Pass them by keyword, because
multipath stays first positional on the site functions.
@gaborbernat
gaborbernat force-pushed the fix/user-preference-dir-app-args branch from 37eda96 to 1b1a5ce Compare August 27, 2026 20:13
@gaborbernat
gaborbernat marked this pull request as ready for review August 27, 2026 20:19
The FBT suppressions were only needed because the booleans were
positional, which is the thing the rule objects to. Both functions took
no arguments before this branch, so nothing can be passing them
positionally and a bare * costs nothing.

That drops seven of the eight suppressions per function. The remaining
too-many-arguments is honest: six options are six options, and every one
of them reaches user_preference_dir through user_config_dir on Unix,
Windows and Android.
@gaborbernat
gaborbernat enabled auto-merge (squash) August 27, 2026 21:17
@gaborbernat
gaborbernat merged commit 2a3ab96 into tox-dev:main Aug 27, 2026
36 checks 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