summaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2026-03-02 19:21:26 +0300
committerrobot-piglet <[email protected]>2026-03-02 21:27:31 +0300
commit83fbb037f31247ccbad309651c665682dd7d88e2 (patch)
treefb591d12d384303cd4ba91ffde768604ea7d15ca /contrib/python
parentaaa2572ec1cd37989cd69a4e8286df17394f756a (diff)
Intermediate changes
commit_hash:15fe475c75799abfa3a20e1c305672191703d12c
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/platformdirs/.dist-info/METADATA61
-rw-r--r--contrib/python/platformdirs/README.md59
-rw-r--r--contrib/python/platformdirs/platformdirs/__init__.py222
-rw-r--r--contrib/python/platformdirs/platformdirs/__main__.py6
-rw-r--r--contrib/python/platformdirs/platformdirs/_xdg.py19
-rw-r--r--contrib/python/platformdirs/platformdirs/android.py32
-rw-r--r--contrib/python/platformdirs/platformdirs/api.py90
-rw-r--r--contrib/python/platformdirs/platformdirs/macos.py50
-rw-r--r--contrib/python/platformdirs/platformdirs/unix.py96
-rw-r--r--contrib/python/platformdirs/platformdirs/version.py4
-rw-r--r--contrib/python/platformdirs/platformdirs/windows.py88
-rw-r--r--contrib/python/platformdirs/ya.make2
-rw-r--r--contrib/python/xmltodict/py3/.dist-info/METADATA18
-rw-r--r--contrib/python/xmltodict/py3/README.md6
-rw-r--r--contrib/python/xmltodict/py3/tests/test_dicttoxml.py12
-rw-r--r--contrib/python/xmltodict/py3/xmltodict.py13
-rw-r--r--contrib/python/xmltodict/py3/ya.make2
17 files changed, 688 insertions, 92 deletions
diff --git a/contrib/python/platformdirs/.dist-info/METADATA b/contrib/python/platformdirs/.dist-info/METADATA
index ee9eb1f16ee..f3e2dcea219 100644
--- a/contrib/python/platformdirs/.dist-info/METADATA
+++ b/contrib/python/platformdirs/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: platformdirs
-Version: 4.7.0
+Version: 4.9.1
Summary: A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`.
Project-URL: Changelog, https://platformdirs.readthedocs.io/en/latest/changelog.html
Project-URL: Documentation, https://platformdirs.readthedocs.io
@@ -44,13 +44,27 @@ differences between macOS, Windows, Linux/Unix, and Android so you don't have to
from platformdirs import PlatformDirs
dirs = PlatformDirs("MyApp", "MyCompany")
-dirs.user_data_dir # e.g. ~/.local/share/MyApp on Linux
-dirs.user_config_dir # e.g. ~/.config/MyApp on Linux
-dirs.user_cache_dir # e.g. ~/.cache/MyApp on Linux
-dirs.user_log_dir # e.g. ~/.local/state/MyApp/log on Linux
+dirs.user_data_dir # ~/.local/share/MyApp (Linux)
+dirs.user_config_dir # ~/.config/MyApp (Linux)
+dirs.user_cache_dir # ~/.cache/MyApp (Linux)
+dirs.user_state_dir # ~/.local/state/MyApp (Linux)
+dirs.user_log_dir # ~/.local/state/MyApp/log (Linux)
+dirs.user_documents_dir # ~/Documents
+dirs.user_downloads_dir # ~/Downloads
+dirs.user_runtime_dir # /run/user/<uid>/MyApp (Linux)
```
-Convenience functions are also available:
+For Path objects instead of strings:
+
+```python
+from platformdirs import PlatformDirs
+
+dirs = PlatformDirs("MyApp", "MyCompany")
+dirs.user_data_path # pathlib.Path('~/.local/share/MyApp')
+dirs.user_config_path # pathlib.Path('~/.config/MyApp')
+```
+
+Convenience functions for quick access:
```python
from platformdirs import user_data_dir, user_config_path
@@ -59,25 +73,28 @@ user_data_dir("MyApp", "MyCompany") # returns str
user_config_path("MyApp", "MyCompany") # returns pathlib.Path
```
-## Documentation
+## Directory types
-Full documentation is available at [platformdirs.readthedocs.io](https://platformdirs.readthedocs.io), including:
+- **Data**: Persistent application data (`user_data_dir`, `site_data_dir`)
+- **Config**: Configuration files and settings (`user_config_dir`, `site_config_dir`)
+- **Cache**: Cached data that can be regenerated (`user_cache_dir`, `site_cache_dir`)
+- **State**: Non-essential runtime state like window positions (`user_state_dir`, `site_state_dir`)
+- **Logs**: Log files (`user_log_dir`, `site_log_dir`)
+- **Runtime**: Runtime files like sockets and PIDs (`user_runtime_dir`, `site_runtime_dir`)
-- [Usage guide](https://platformdirs.readthedocs.io/en/latest/usage.html) -- parameters, examples, and patterns
-- [API reference](https://platformdirs.readthedocs.io/en/latest/api.html) -- all functions and classes
-- [Platform details](https://platformdirs.readthedocs.io/en/latest/platforms.html) -- per-platform paths and behavior
+Each type has both `user_*` (per-user, writable) and `site_*` (system-wide, read-only for users) variants.
-## Why this fork?
-
-This repository is a friendly fork of the wonderful work started by
-[ActiveState](https://github.com/ActiveState/appdirs) who created `appdirs`, this package's ancestor.
+## Documentation
-Maintaining an open source project is no easy task, particularly from within an organization, and the Python community
-is indebted to `appdirs` (and to Trent Mick and Jeff Rouse in particular) for creating an incredibly useful simple
-module, as evidenced by the wide number of users it has attracted over the years.
+Full documentation is available at [platformdirs.readthedocs.io](https://platformdirs.readthedocs.io):
-Nonetheless, given the number of long-standing open issues and pull requests, and no clear path towards
-[ensuring that maintenance of the package would continue or grow](https://github.com/ActiveState/appdirs/issues/79),
-this fork was created.
+- **[Getting started tutorial](https://platformdirs.readthedocs.io/en/latest/usage.html)** -- learn core concepts
+ through real-world examples
+- **[How-to guides](https://platformdirs.readthedocs.io/en/latest/howto.html)** -- recipes for common tasks and
+ platform-specific tips
+- **[API reference](https://platformdirs.readthedocs.io/en/latest/api.html)** -- complete list of functions and classes
+- **[Platform details](https://platformdirs.readthedocs.io/en/latest/platforms.html)** -- default paths for each
+ operating system
-Contributions are most welcome.
+Contributions are welcome! See [CONTRIBUTING.md](https://github.com/tox-dev/platformdirs/blob/main/CONTRIBUTING.md) for
+details.
diff --git a/contrib/python/platformdirs/README.md b/contrib/python/platformdirs/README.md
index 04779d681ff..4642eac68f7 100644
--- a/contrib/python/platformdirs/README.md
+++ b/contrib/python/platformdirs/README.md
@@ -14,13 +14,27 @@ differences between macOS, Windows, Linux/Unix, and Android so you don't have to
from platformdirs import PlatformDirs
dirs = PlatformDirs("MyApp", "MyCompany")
-dirs.user_data_dir # e.g. ~/.local/share/MyApp on Linux
-dirs.user_config_dir # e.g. ~/.config/MyApp on Linux
-dirs.user_cache_dir # e.g. ~/.cache/MyApp on Linux
-dirs.user_log_dir # e.g. ~/.local/state/MyApp/log on Linux
+dirs.user_data_dir # ~/.local/share/MyApp (Linux)
+dirs.user_config_dir # ~/.config/MyApp (Linux)
+dirs.user_cache_dir # ~/.cache/MyApp (Linux)
+dirs.user_state_dir # ~/.local/state/MyApp (Linux)
+dirs.user_log_dir # ~/.local/state/MyApp/log (Linux)
+dirs.user_documents_dir # ~/Documents
+dirs.user_downloads_dir # ~/Downloads
+dirs.user_runtime_dir # /run/user/<uid>/MyApp (Linux)
```
-Convenience functions are also available:
+For Path objects instead of strings:
+
+```python
+from platformdirs import PlatformDirs
+
+dirs = PlatformDirs("MyApp", "MyCompany")
+dirs.user_data_path # pathlib.Path('~/.local/share/MyApp')
+dirs.user_config_path # pathlib.Path('~/.config/MyApp')
+```
+
+Convenience functions for quick access:
```python
from platformdirs import user_data_dir, user_config_path
@@ -29,25 +43,28 @@ user_data_dir("MyApp", "MyCompany") # returns str
user_config_path("MyApp", "MyCompany") # returns pathlib.Path
```
-## Documentation
+## Directory types
-Full documentation is available at [platformdirs.readthedocs.io](https://platformdirs.readthedocs.io), including:
+- **Data**: Persistent application data (`user_data_dir`, `site_data_dir`)
+- **Config**: Configuration files and settings (`user_config_dir`, `site_config_dir`)
+- **Cache**: Cached data that can be regenerated (`user_cache_dir`, `site_cache_dir`)
+- **State**: Non-essential runtime state like window positions (`user_state_dir`, `site_state_dir`)
+- **Logs**: Log files (`user_log_dir`, `site_log_dir`)
+- **Runtime**: Runtime files like sockets and PIDs (`user_runtime_dir`, `site_runtime_dir`)
-- [Usage guide](https://platformdirs.readthedocs.io/en/latest/usage.html) -- parameters, examples, and patterns
-- [API reference](https://platformdirs.readthedocs.io/en/latest/api.html) -- all functions and classes
-- [Platform details](https://platformdirs.readthedocs.io/en/latest/platforms.html) -- per-platform paths and behavior
+Each type has both `user_*` (per-user, writable) and `site_*` (system-wide, read-only for users) variants.
-## Why this fork?
-
-This repository is a friendly fork of the wonderful work started by
-[ActiveState](https://github.com/ActiveState/appdirs) who created `appdirs`, this package's ancestor.
+## Documentation
-Maintaining an open source project is no easy task, particularly from within an organization, and the Python community
-is indebted to `appdirs` (and to Trent Mick and Jeff Rouse in particular) for creating an incredibly useful simple
-module, as evidenced by the wide number of users it has attracted over the years.
+Full documentation is available at [platformdirs.readthedocs.io](https://platformdirs.readthedocs.io):
-Nonetheless, given the number of long-standing open issues and pull requests, and no clear path towards
-[ensuring that maintenance of the package would continue or grow](https://github.com/ActiveState/appdirs/issues/79),
-this fork was created.
+- **[Getting started tutorial](https://platformdirs.readthedocs.io/en/latest/usage.html)** -- learn core concepts
+ through real-world examples
+- **[How-to guides](https://platformdirs.readthedocs.io/en/latest/howto.html)** -- recipes for common tasks and
+ platform-specific tips
+- **[API reference](https://platformdirs.readthedocs.io/en/latest/api.html)** -- complete list of functions and classes
+- **[Platform details](https://platformdirs.readthedocs.io/en/latest/platforms.html)** -- default paths for each
+ operating system
-Contributions are most welcome.
+Contributions are welcome! See [CONTRIBUTING.md](https://github.com/tox-dev/platformdirs/blob/main/CONTRIBUTING.md) for
+details.
diff --git a/contrib/python/platformdirs/platformdirs/__init__.py b/contrib/python/platformdirs/platformdirs/__init__.py
index 7896bf67b04..fb530c92998 100644
--- a/contrib/python/platformdirs/platformdirs/__init__.py
+++ b/contrib/python/platformdirs/platformdirs/__init__.py
@@ -53,12 +53,13 @@ else:
AppDirs = PlatformDirs #: Backwards compatibility with appdirs
-def user_data_dir(
+def user_data_dir( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
roaming: bool = False, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -66,6 +67,7 @@ def user_data_dir(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: data directory tied to the user
"""
return PlatformDirs(
@@ -74,6 +76,7 @@ def user_data_dir(
version=version,
roaming=roaming,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_data_dir
@@ -101,12 +104,13 @@ def site_data_dir(
).site_data_dir
-def user_config_dir(
+def user_config_dir( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
roaming: bool = False, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -114,6 +118,7 @@ def user_config_dir(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: config directory tied to the user
"""
return PlatformDirs(
@@ -122,6 +127,7 @@ def user_config_dir(
version=version,
roaming=roaming,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_config_dir
@@ -149,12 +155,13 @@ def site_config_dir(
).site_config_dir
-def user_cache_dir(
+def user_cache_dir( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -162,6 +169,7 @@ def user_cache_dir(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: cache directory tied to the user
"""
return PlatformDirs(
@@ -170,6 +178,7 @@ def user_cache_dir(
version=version,
opinion=opinion,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_cache_dir
@@ -197,12 +206,13 @@ def site_cache_dir(
).site_cache_dir
-def user_state_dir(
+def user_state_dir( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
roaming: bool = False, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -210,6 +220,7 @@ def user_state_dir(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: state directory tied to the user
"""
return PlatformDirs(
@@ -218,15 +229,38 @@ def user_state_dir(
version=version,
roaming=roaming,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_state_dir
-def user_log_dir(
+def site_state_dir(
+ appname: str | None = None,
+ appauthor: str | Literal[False] | None = None,
+ version: str | None = None,
+ ensure_exists: bool = False, # noqa: FBT001, FBT002
+) -> str:
+ """
+ :param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
+ :param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
+ :param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
+ :param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :returns: state directory shared by users
+ """
+ return PlatformDirs(
+ appname=appname,
+ appauthor=appauthor,
+ version=version,
+ ensure_exists=ensure_exists,
+ ).site_state_dir
+
+
+def user_log_dir( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -234,6 +268,7 @@ def user_log_dir(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: log directory tied to the user
"""
return PlatformDirs(
@@ -242,9 +277,34 @@ def user_log_dir(
version=version,
opinion=opinion,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_log_dir
+def site_log_dir(
+ appname: str | None = None,
+ appauthor: str | Literal[False] | None = None,
+ version: str | None = None,
+ opinion: bool = True, # noqa: FBT001, FBT002
+ ensure_exists: bool = False, # noqa: FBT001, FBT002
+) -> str:
+ """
+ :param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
+ :param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
+ :param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
+ :param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
+ :param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :returns: log directory shared by users
+ """
+ return PlatformDirs(
+ appname=appname,
+ appauthor=appauthor,
+ version=version,
+ opinion=opinion,
+ ensure_exists=ensure_exists,
+ ).site_log_dir
+
+
def user_documents_dir() -> str:
""":returns: documents directory tied to the user"""
return PlatformDirs().user_documents_dir
@@ -275,12 +335,43 @@ def user_desktop_dir() -> str:
return PlatformDirs().user_desktop_dir
-def user_runtime_dir(
+def user_bin_dir() -> str:
+ """:returns: bin directory tied to the user"""
+ return PlatformDirs().user_bin_dir
+
+
+def site_bin_dir() -> str:
+ """:returns: bin directory shared by users"""
+ return PlatformDirs().site_bin_dir
+
+
+def user_applications_dir() -> str:
+ """:returns: applications directory tied to the user"""
+ return PlatformDirs().user_applications_dir
+
+
+def site_applications_dir(
+ multipath: bool = False, # noqa: FBT001, FBT002
+ ensure_exists: bool = False, # noqa: FBT001, FBT002
+) -> str:
+ """
+ :param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
+ :param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :returns: applications directory shared by users
+ """
+ return PlatformDirs(
+ multipath=multipath,
+ ensure_exists=ensure_exists,
+ ).site_applications_dir
+
+
+def user_runtime_dir( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -288,6 +379,7 @@ def user_runtime_dir(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: runtime directory tied to the user
"""
return PlatformDirs(
@@ -296,6 +388,7 @@ def user_runtime_dir(
version=version,
opinion=opinion,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_runtime_dir
@@ -323,12 +416,13 @@ def site_runtime_dir(
).site_runtime_dir
-def user_data_path(
+def user_data_path( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
roaming: bool = False, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -336,6 +430,7 @@ def user_data_path(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: data path tied to the user
"""
return PlatformDirs(
@@ -344,6 +439,7 @@ def user_data_path(
version=version,
roaming=roaming,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_data_path
@@ -371,12 +467,13 @@ def site_data_path(
).site_data_path
-def user_config_path(
+def user_config_path( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
roaming: bool = False, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -384,6 +481,7 @@ def user_config_path(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: config path tied to the user
"""
return PlatformDirs(
@@ -392,6 +490,7 @@ def user_config_path(
version=version,
roaming=roaming,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_config_path
@@ -443,12 +542,13 @@ def site_cache_path(
).site_cache_path
-def user_cache_path(
+def user_cache_path( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -456,6 +556,7 @@ def user_cache_path(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: cache path tied to the user
"""
return PlatformDirs(
@@ -464,15 +565,17 @@ def user_cache_path(
version=version,
opinion=opinion,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_cache_path
-def user_state_path(
+def user_state_path( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
roaming: bool = False, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -480,6 +583,7 @@ def user_state_path(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: state path tied to the user
"""
return PlatformDirs(
@@ -488,15 +592,38 @@ def user_state_path(
version=version,
roaming=roaming,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_state_path
-def user_log_path(
+def site_state_path(
+ appname: str | None = None,
+ appauthor: str | Literal[False] | None = None,
+ version: str | None = None,
+ ensure_exists: bool = False, # noqa: FBT001, FBT002
+) -> Path:
+ """
+ :param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
+ :param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
+ :param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
+ :param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :returns: state path shared by users
+ """
+ return PlatformDirs(
+ appname=appname,
+ appauthor=appauthor,
+ version=version,
+ ensure_exists=ensure_exists,
+ ).site_state_path
+
+
+def user_log_path( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -504,6 +631,7 @@ def user_log_path(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: log path tied to the user
"""
return PlatformDirs(
@@ -512,9 +640,34 @@ def user_log_path(
version=version,
opinion=opinion,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_log_path
+def site_log_path(
+ appname: str | None = None,
+ appauthor: str | Literal[False] | None = None,
+ version: str | None = None,
+ opinion: bool = True, # noqa: FBT001, FBT002
+ ensure_exists: bool = False, # noqa: FBT001, FBT002
+) -> Path:
+ """
+ :param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
+ :param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
+ :param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
+ :param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
+ :param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :returns: log path shared by users
+ """
+ return PlatformDirs(
+ appname=appname,
+ appauthor=appauthor,
+ version=version,
+ opinion=opinion,
+ ensure_exists=ensure_exists,
+ ).site_log_path
+
+
def user_documents_path() -> Path:
""":returns: documents path tied to the user"""
return PlatformDirs().user_documents_path
@@ -545,12 +698,43 @@ def user_desktop_path() -> Path:
return PlatformDirs().user_desktop_path
-def user_runtime_path(
+def user_bin_path() -> Path:
+ """:returns: bin path tied to the user"""
+ return PlatformDirs().user_bin_path
+
+
+def site_bin_path() -> Path:
+ """:returns: bin path shared by users"""
+ return PlatformDirs().site_bin_path
+
+
+def user_applications_path() -> Path:
+ """:returns: applications path tied to the user"""
+ return PlatformDirs().user_applications_path
+
+
+def site_applications_path(
+ multipath: bool = False, # noqa: FBT001, FBT002
+ ensure_exists: bool = False, # noqa: FBT001, FBT002
+) -> Path:
+ """
+ :param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
+ :param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :returns: applications path shared by users
+ """
+ return PlatformDirs(
+ multipath=multipath,
+ ensure_exists=ensure_exists,
+ ).site_applications_path
+
+
+def user_runtime_path( # noqa: PLR0913, PLR0917
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
@@ -558,6 +742,7 @@ def user_runtime_path(
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
+ :param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
:returns: runtime path tied to the user
"""
return PlatformDirs(
@@ -566,6 +751,7 @@ def user_runtime_path(
version=version,
opinion=opinion,
ensure_exists=ensure_exists,
+ use_site_for_root=use_site_for_root,
).user_runtime_path
@@ -599,14 +785,26 @@ __all__ = [
"PlatformDirsABC",
"__version__",
"__version_info__",
+ "site_applications_dir",
+ "site_applications_path",
+ "site_bin_dir",
+ "site_bin_path",
"site_cache_dir",
"site_cache_path",
"site_config_dir",
"site_config_path",
"site_data_dir",
"site_data_path",
+ "site_log_dir",
+ "site_log_path",
"site_runtime_dir",
"site_runtime_path",
+ "site_state_dir",
+ "site_state_path",
+ "user_applications_dir",
+ "user_applications_path",
+ "user_bin_dir",
+ "user_bin_path",
"user_cache_dir",
"user_cache_path",
"user_config_dir",
diff --git a/contrib/python/platformdirs/platformdirs/__main__.py b/contrib/python/platformdirs/platformdirs/__main__.py
index 922c521358e..2490ffbbe1b 100644
--- a/contrib/python/platformdirs/platformdirs/__main__.py
+++ b/contrib/python/platformdirs/platformdirs/__main__.py
@@ -15,10 +15,16 @@ PROPS = (
"user_pictures_dir",
"user_videos_dir",
"user_music_dir",
+ "user_bin_dir",
+ "site_bin_dir",
+ "user_applications_dir",
"user_runtime_dir",
"site_data_dir",
"site_config_dir",
"site_cache_dir",
+ "site_state_dir",
+ "site_log_dir",
+ "site_applications_dir",
"site_runtime_dir",
)
diff --git a/contrib/python/platformdirs/platformdirs/_xdg.py b/contrib/python/platformdirs/platformdirs/_xdg.py
index 59765ebdf2c..4060e89f434 100644
--- a/contrib/python/platformdirs/platformdirs/_xdg.py
+++ b/contrib/python/platformdirs/platformdirs/_xdg.py
@@ -118,6 +118,25 @@ class XDGMixin(PlatformDirsABC):
return os.path.expanduser(path) # noqa: PTH111
return super().user_desktop_dir
+ @property
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user, from ``$XDG_DATA_HOME`` if set, else platform default"""
+ if path := os.environ.get("XDG_DATA_HOME", "").strip():
+ return os.path.join(os.path.expanduser(path), "applications") # noqa: PTH111, PTH118
+ return super().user_applications_dir
+
+ @property
+ def _site_applications_dirs(self) -> list[str]:
+ if xdg_dirs := os.environ.get("XDG_DATA_DIRS", "").strip():
+ return [os.path.join(p, "applications") for p in xdg_dirs.split(os.pathsep) if p.strip()] # noqa: PTH118
+ return super()._site_applications_dirs # type: ignore[misc]
+
+ @property
+ def site_applications_dir(self) -> str:
+ """:return: applications directories shared by users, from ``$XDG_DATA_DIRS`` if set, else platform default"""
+ dirs = self._site_applications_dirs
+ return os.pathsep.join(dirs) if self.multipath else dirs[0]
+
__all__ = [
"XDGMixin",
diff --git a/contrib/python/platformdirs/platformdirs/android.py b/contrib/python/platformdirs/platformdirs/android.py
index dec1e5eb044..708355bf1a8 100644
--- a/contrib/python/platformdirs/platformdirs/android.py
+++ b/contrib/python/platformdirs/platformdirs/android.py
@@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, cast
from .api import PlatformDirsABC
-class Android(PlatformDirsABC):
+class Android(PlatformDirsABC): # noqa: PLR0904
"""
Platform directories for Android.
@@ -63,6 +63,11 @@ class Android(PlatformDirsABC):
return self.user_data_dir
@property
+ def site_state_dir(self) -> str:
+ """:return: state directory shared by users, same as `user_state_dir`"""
+ return self.user_state_dir
+
+ @property
def user_log_dir(self) -> str:
"""
:return: log directory tied to the user, same as `user_cache_dir` if not opinionated else ``log`` in it,
@@ -74,6 +79,11 @@ class Android(PlatformDirsABC):
return path
@property
+ def site_log_dir(self) -> str:
+ """:return: log directory shared by users, same as `user_log_dir`"""
+ return self.user_log_dir
+
+ @property
def user_documents_dir(self) -> str:
""":return: documents directory tied to the user e.g. ``/storage/emulated/0/Documents``"""
return _android_documents_folder()
@@ -104,6 +114,26 @@ class Android(PlatformDirsABC):
return "/storage/emulated/0/Desktop"
@property
+ def user_bin_dir(self) -> str:
+ """:return: bin directory tied to the user, e.g. ``/data/user/<userid>/<packagename>/files/bin``"""
+ return os.path.join(cast("str", _android_folder()), "files", "bin") # noqa: PTH118
+
+ @property
+ def site_bin_dir(self) -> str:
+ """:return: bin directory shared by users, same as `user_bin_dir`"""
+ return self.user_bin_dir
+
+ @property
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user, same as `user_data_dir`"""
+ return self.user_data_dir
+
+ @property
+ def site_applications_dir(self) -> str:
+ """:return: applications directory shared by users, same as `user_applications_dir`"""
+ return self.user_applications_dir
+
+ @property
def user_runtime_dir(self) -> str:
"""
:return: runtime directory tied to the user, same as `user_cache_dir` if not opinionated else ``tmp`` in it,
diff --git a/contrib/python/platformdirs/platformdirs/api.py b/contrib/python/platformdirs/platformdirs/api.py
index 1e038d8b5d2..46afe0a82f8 100644
--- a/contrib/python/platformdirs/platformdirs/api.py
+++ b/contrib/python/platformdirs/platformdirs/api.py
@@ -32,6 +32,7 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
multipath: bool = False, # noqa: FBT001, FBT002
opinion: bool = True, # noqa: FBT001, FBT002
ensure_exists: bool = False, # noqa: FBT001, FBT002
+ use_site_for_root: bool = False, # noqa: FBT001, FBT002
) -> None:
"""
Create a new platform directory.
@@ -43,6 +44,7 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
:param multipath: See `multipath`.
:param opinion: See `opinion`.
:param ensure_exists: See `ensure_exists`.
+ :param use_site_for_root: See `use_site_for_root`.
"""
self.appname = appname #: The name of the application.
@@ -93,6 +95,14 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
By default, no directories are created.
"""
+ self.use_site_for_root = use_site_for_root
+ """
+ Whether to redirect ``user_*_dir`` calls to their ``site_*_dir`` equivalents when running as root (uid 0).
+
+ Only has an effect on Unix. Disabled by default for backwards compatibility. When enabled, XDG user environment
+ variables (e.g. ``XDG_DATA_HOME``) are bypassed for the redirected directories.
+
+ """
def _append_app_name_and_version(self, *base: str) -> str:
params = list(base[1:])
@@ -151,11 +161,21 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
@property
@abstractmethod
+ def site_state_dir(self) -> str:
+ """:return: state directory shared by users"""
+
+ @property
+ @abstractmethod
def user_log_dir(self) -> str:
""":return: log directory tied to the user"""
@property
@abstractmethod
+ def site_log_dir(self) -> str:
+ """:return: log directory shared by users"""
+
+ @property
+ @abstractmethod
def user_documents_dir(self) -> str:
""":return: documents directory tied to the user"""
@@ -186,6 +206,26 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
@property
@abstractmethod
+ def user_bin_dir(self) -> str:
+ """:return: bin directory tied to the user"""
+
+ @property
+ @abstractmethod
+ def site_bin_dir(self) -> str:
+ """:return: bin directory shared by users"""
+
+ @property
+ @abstractmethod
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user"""
+
+ @property
+ @abstractmethod
+ def site_applications_dir(self) -> str:
+ """:return: applications directory shared by users"""
+
+ @property
+ @abstractmethod
def user_runtime_dir(self) -> str:
""":return: runtime directory tied to the user"""
@@ -230,11 +270,21 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
return Path(self.user_state_dir)
@property
+ def site_state_path(self) -> Path:
+ """:return: state path shared by users"""
+ return Path(self.site_state_dir)
+
+ @property
def user_log_path(self) -> Path:
""":return: log path tied to the user"""
return Path(self.user_log_dir)
@property
+ def site_log_path(self) -> Path:
+ """:return: log path shared by users"""
+ return Path(self.site_log_dir)
+
+ @property
def user_documents_path(self) -> Path:
""":return: documents path tied to the user"""
return Path(self.user_documents_dir)
@@ -265,6 +315,26 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
return Path(self.user_desktop_dir)
@property
+ def user_bin_path(self) -> Path:
+ """:return: bin path tied to the user"""
+ return Path(self.user_bin_dir)
+
+ @property
+ def site_bin_path(self) -> Path:
+ """:return: bin path shared by users"""
+ return Path(self.site_bin_dir)
+
+ @property
+ def user_applications_path(self) -> Path:
+ """:return: applications path tied to the user"""
+ return Path(self.user_applications_dir)
+
+ @property
+ def site_applications_path(self) -> Path:
+ """:return: applications path shared by users"""
+ return Path(self.site_applications_dir)
+
+ @property
def user_runtime_path(self) -> Path:
""":return: runtime path tied to the user"""
return Path(self.user_runtime_dir)
@@ -289,6 +359,16 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
yield self.user_cache_dir
yield self.site_cache_dir
+ def iter_state_dirs(self) -> Iterator[str]:
+ """:yield: all user and site state directories."""
+ yield self.user_state_dir
+ yield self.site_state_dir
+
+ def iter_log_dirs(self) -> Iterator[str]:
+ """:yield: all user and site log directories."""
+ yield self.user_log_dir
+ yield self.site_log_dir
+
def iter_runtime_dirs(self) -> Iterator[str]:
""":yield: all user and site runtime directories."""
yield self.user_runtime_dir
@@ -309,6 +389,16 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
for path in self.iter_cache_dirs():
yield Path(path)
+ def iter_state_paths(self) -> Iterator[Path]:
+ """:yield: all user and site state paths."""
+ for path in self.iter_state_dirs():
+ yield Path(path)
+
+ def iter_log_paths(self) -> Iterator[Path]:
+ """:yield: all user and site log paths."""
+ for path in self.iter_log_dirs():
+ yield Path(path)
+
def iter_runtime_paths(self) -> Iterator[Path]:
""":yield: all user and site runtime paths."""
for path in self.iter_runtime_dirs():
diff --git a/contrib/python/platformdirs/platformdirs/macos.py b/contrib/python/platformdirs/platformdirs/macos.py
index 80a6c7348f0..3343a0bfffc 100644
--- a/contrib/python/platformdirs/platformdirs/macos.py
+++ b/contrib/python/platformdirs/platformdirs/macos.py
@@ -6,6 +6,9 @@ import os.path
import sys
from typing import TYPE_CHECKING
+if TYPE_CHECKING:
+ from collections.abc import Iterator
+
from ._xdg import XDGMixin
from .api import PlatformDirsABC
@@ -13,7 +16,7 @@ if TYPE_CHECKING:
from pathlib import Path
-class _MacOSDefaults(PlatformDirsABC):
+class _MacOSDefaults(PlatformDirsABC): # noqa: PLR0904
"""
Default platform directories for macOS without XDG environment variable overrides.
@@ -83,11 +86,21 @@ class _MacOSDefaults(PlatformDirsABC):
return self.user_data_dir
@property
+ def site_state_dir(self) -> str:
+ """:return: state directory shared by users, same as `site_data_dir`"""
+ return self.site_data_dir
+
+ @property
def user_log_dir(self) -> str:
""":return: log directory tied to the user, e.g. ``~/Library/Logs/$appname/$version``"""
return self._append_app_name_and_version(os.path.expanduser("~/Library/Logs")) # noqa: PTH111
@property
+ def site_log_dir(self) -> str:
+ """:return: log directory shared by users, e.g. ``/Library/Logs/$appname/$version``"""
+ return self._append_app_name_and_version("/Library/Logs")
+
+ @property
def user_documents_dir(self) -> str:
""":return: documents directory tied to the user, e.g. ``~/Documents``"""
return os.path.expanduser("~/Documents") # noqa: PTH111
@@ -118,6 +131,31 @@ class _MacOSDefaults(PlatformDirsABC):
return os.path.expanduser("~/Desktop") # noqa: PTH111
@property
+ def user_bin_dir(self) -> str:
+ """:return: bin directory tied to the user, e.g. ``~/.local/bin``"""
+ return os.path.expanduser("~/.local/bin") # noqa: PTH111
+
+ @property
+ def site_bin_dir(self) -> str:
+ """:return: bin directory shared by users, e.g. ``/usr/local/bin``"""
+ return "/usr/local/bin"
+
+ @property
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user, e.g. ``~/Applications``"""
+ return os.path.expanduser("~/Applications") # noqa: PTH111
+
+ @property
+ def _site_applications_dirs(self) -> list[str]:
+ return ["/Applications"]
+
+ @property
+ def site_applications_dir(self) -> str:
+ """:return: applications directory shared by users, e.g. ``/Applications``"""
+ dirs = self._site_applications_dirs
+ return os.pathsep.join(dirs) if self.multipath else dirs[0]
+
+ @property
def user_runtime_dir(self) -> str:
""":return: runtime directory tied to the user, e.g. ``~/Library/Caches/TemporaryItems/$appname/$version``"""
return self._append_app_name_and_version(os.path.expanduser("~/Library/Caches/TemporaryItems")) # noqa: PTH111
@@ -127,6 +165,16 @@ class _MacOSDefaults(PlatformDirsABC):
""":return: runtime directory shared by users, same as `user_runtime_dir`"""
return self.user_runtime_dir
+ def iter_config_dirs(self) -> Iterator[str]:
+ """:yield: all user and site configuration directories."""
+ yield self.user_config_dir
+ yield from self._site_config_dirs
+
+ def iter_data_dirs(self) -> Iterator[str]:
+ """:yield: all user and site data directories."""
+ yield self.user_data_dir
+ yield from self._site_data_dirs
+
class MacOS(XDGMixin, _MacOSDefaults):
"""
diff --git a/contrib/python/platformdirs/platformdirs/unix.py b/contrib/python/platformdirs/platformdirs/unix.py
index d0cb6719d9e..e388fcbd2d7 100644
--- a/contrib/python/platformdirs/platformdirs/unix.py
+++ b/contrib/python/platformdirs/platformdirs/unix.py
@@ -5,6 +5,7 @@ from __future__ import annotations
import os
import sys
from configparser import ConfigParser
+from functools import cached_property
from pathlib import Path
from tempfile import gettempdir
from typing import TYPE_CHECKING, NoReturn
@@ -25,13 +26,17 @@ else:
from os import getuid
-class _UnixDefaults(PlatformDirsABC):
+class _UnixDefaults(PlatformDirsABC): # noqa: PLR0904
"""
Default directories for Unix/Linux without XDG environment variable overrides.
The XDG env var handling is in :class:`~platformdirs._xdg.XDGMixin`.
"""
+ @cached_property
+ def _use_site(self) -> bool:
+ return self.use_site_for_root and getuid() == 0
+
@property
def user_data_dir(self) -> str:
"""
@@ -78,6 +83,11 @@ class _UnixDefaults(PlatformDirsABC):
return self._append_app_name_and_version(os.path.expanduser("~/.local/state")) # noqa: PTH111
@property
+ def site_state_dir(self) -> str:
+ """:return: state directory shared by users, e.g. ``/var/lib/$appname/$version``"""
+ return self._append_app_name_and_version("/var/lib")
+
+ @property
def user_log_dir(self) -> str:
""":return: log directory tied to the user, same as `user_state_dir` if not opinionated else ``log`` in it"""
path = self.user_state_dir
@@ -87,6 +97,15 @@ class _UnixDefaults(PlatformDirsABC):
return path
@property
+ def site_log_dir(self) -> str:
+ """
+ :return: log directory shared by users, e.g. ``/var/log/$appname/$version``
+
+ Unlike `user_log_dir`, ``opinion`` has no effect since ``/var/log`` is inherently a log directory.
+ """
+ return self._append_app_name_and_version("/var/log")
+
+ @property
def user_documents_dir(self) -> str:
""":return: documents directory tied to the user, e.g. ``~/Documents``"""
return _get_user_media_dir("XDG_DOCUMENTS_DIR", "~/Documents")
@@ -117,15 +136,42 @@ class _UnixDefaults(PlatformDirsABC):
return _get_user_media_dir("XDG_DESKTOP_DIR", "~/Desktop")
@property
+ def user_bin_dir(self) -> str:
+ """:return: bin directory tied to the user, e.g. ``~/.local/bin``"""
+ return os.path.expanduser("~/.local/bin") # noqa: PTH111
+
+ @property
+ def site_bin_dir(self) -> str:
+ """:return: bin directory shared by users, e.g. ``/usr/local/bin``"""
+ return "/usr/local/bin"
+
+ @property
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user, e.g. ``~/.local/share/applications``"""
+ return os.path.join(os.path.expanduser("~/.local/share"), "applications") # noqa: PTH111, PTH118
+
+ @property
+ def _site_applications_dirs(self) -> list[str]:
+ return [os.path.join(p, "applications") for p in ["/usr/local/share", "/usr/share"]] # noqa: PTH118
+
+ @property
+ def site_applications_dir(self) -> str:
+ """:return: applications directory shared by users, e.g. ``/usr/share/applications``"""
+ dirs = self._site_applications_dirs
+ return os.pathsep.join(dirs) if self.multipath else dirs[0]
+
+ @property
def user_runtime_dir(self) -> str:
"""
:return: runtime directory tied to the user, e.g. ``$XDG_RUNTIME_DIR/$appname/$version``.
- If ``$XDG_RUNTIME_DIR`` is unset, tries the platform default (``/var/run/user/$(id -u)`` on
- FreeBSD/OpenBSD/NetBSD, ``/run/user/$(id -u)`` otherwise). If the default is not writable,
- falls back to a temporary directory.
+ If ``$XDG_RUNTIME_DIR`` is unset, tries the platform default (``/tmp/run/user/$(id -u)`` on
+ OpenBSD, ``/var/run/user/$(id -u)`` on FreeBSD/NetBSD, ``/run/user/$(id -u)`` otherwise).
+ If the default is not writable, falls back to a temporary directory.
"""
- if sys.platform.startswith(("freebsd", "openbsd", "netbsd")):
+ if sys.platform.startswith("openbsd"):
+ path = f"/tmp/run/user/{getuid()}" # noqa: S108
+ elif sys.platform.startswith(("freebsd", "netbsd")):
path = f"/var/run/user/{getuid()}"
else:
path = f"/run/user/{getuid()}"
@@ -190,6 +236,46 @@ class Unix(XDGMixin, _UnixDefaults):
<platformdirs.api.PlatformDirsABC.ensure_exists>`.
"""
+ @property
+ def user_data_dir(self) -> str:
+ """:return: data directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_data_dir if self._use_site else super().user_data_dir
+
+ @property
+ def user_config_dir(self) -> str:
+ """:return: config directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_config_dir if self._use_site else super().user_config_dir
+
+ @property
+ def user_cache_dir(self) -> str:
+ """:return: cache directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_cache_dir if self._use_site else super().user_cache_dir
+
+ @property
+ def user_state_dir(self) -> str:
+ """:return: state directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_state_dir if self._use_site else super().user_state_dir
+
+ @property
+ def user_log_dir(self) -> str:
+ """:return: log directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_log_dir if self._use_site else super().user_log_dir
+
+ @property
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_applications_dir if self._use_site else super().user_applications_dir
+
+ @property
+ def user_runtime_dir(self) -> str:
+ """:return: runtime directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_runtime_dir if self._use_site else super().user_runtime_dir
+
+ @property
+ def user_bin_dir(self) -> str:
+ """:return: bin directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
+ return self.site_bin_dir if self._use_site else super().user_bin_dir
+
def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str:
if media_dir := _get_user_dirs_folder(env_var):
diff --git a/contrib/python/platformdirs/platformdirs/version.py b/contrib/python/platformdirs/platformdirs/version.py
index f00ce0cd04a..1ad854cdb25 100644
--- a/contrib/python/platformdirs/platformdirs/version.py
+++ b/contrib/python/platformdirs/platformdirs/version.py
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
commit_id: COMMIT_ID
__commit_id__: COMMIT_ID
-__version__ = version = '4.7.0'
-__version_tuple__ = version_tuple = (4, 7, 0)
+__version__ = version = '4.9.1'
+__version_tuple__ = version_tuple = (4, 9, 1)
__commit_id__ = commit_id = None
diff --git a/contrib/python/platformdirs/platformdirs/windows.py b/contrib/python/platformdirs/platformdirs/windows.py
index 838e07fad60..84afaa75565 100644
--- a/contrib/python/platformdirs/platformdirs/windows.py
+++ b/contrib/python/platformdirs/platformdirs/windows.py
@@ -4,16 +4,18 @@ from __future__ import annotations
import os
import sys
-from functools import lru_cache
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Final
from .api import PlatformDirsABC
if TYPE_CHECKING:
from collections.abc import Callable
+# Not exposed by CPython; defined in the Windows SDK (shlobj_core.h)
+_KF_FLAG_DONT_VERIFY: Final[int] = 0x00004000
-class Windows(PlatformDirsABC):
+
+class Windows(PlatformDirsABC): # noqa: PLR0904
"""
`MSDN on where to store app data files <https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid>`_.
@@ -87,6 +89,11 @@ class Windows(PlatformDirsABC):
return self.user_data_dir
@property
+ def site_state_dir(self) -> str:
+ """:return: state directory shared by users, same as `site_data_dir`"""
+ return self.site_data_dir
+
+ @property
def user_log_dir(self) -> str:
""":return: log directory tied to the user, same as `user_data_dir` if not opinionated else ``Logs`` in it"""
path = self.user_data_dir
@@ -96,6 +103,15 @@ class Windows(PlatformDirsABC):
return path
@property
+ def site_log_dir(self) -> str:
+ """:return: log directory shared by users, same as `site_data_dir` if not opinionated else ``Logs`` in it"""
+ path = self.site_data_dir
+ if self.opinion:
+ path = os.path.join(path, "Logs") # noqa: PTH118
+ self._optionally_create_directory(path)
+ return path
+
+ @property
def user_documents_dir(self) -> str:
""":return: documents directory tied to the user e.g. ``%USERPROFILE%\\Documents``"""
return os.path.normpath(get_win_folder("CSIDL_PERSONAL"))
@@ -126,6 +142,29 @@ class Windows(PlatformDirsABC):
return os.path.normpath(get_win_folder("CSIDL_DESKTOPDIRECTORY"))
@property
+ def user_bin_dir(self) -> str:
+ """:return: bin directory tied to the user, e.g. ``%LOCALAPPDATA%\\Programs``"""
+ return os.path.normpath(os.path.join(get_win_folder("CSIDL_LOCAL_APPDATA"), "Programs")) # noqa: PTH118
+
+ @property
+ def site_bin_dir(self) -> str:
+ """:return: bin directory shared by users, e.g. ``C:\\ProgramData\\bin``"""
+ return os.path.normpath(os.path.join(get_win_folder("CSIDL_COMMON_APPDATA"), "bin")) # noqa: PTH118
+
+ @property
+ def user_applications_dir(self) -> str:
+ """:return: applications directory tied to the user, e.g. ``Start Menu\\Programs``"""
+ return os.path.normpath(get_win_folder("CSIDL_PROGRAMS"))
+
+ @property
+ def site_applications_dir(self) -> str:
+ """
+ :return: applications directory shared by users, e.g. \
+ ``C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs``
+ """
+ return os.path.normpath(get_win_folder("CSIDL_COMMON_PROGRAMS"))
+
+ @property
def user_runtime_dir(self) -> str:
"""
:return: runtime directory tied to the user, e.g.
@@ -161,7 +200,7 @@ def get_win_folder_from_env_vars(csidl_name: str) -> str:
return result
-def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None:
+def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None: # noqa: PLR0911
"""Get a folder for a CSIDL name that does not exist as an environment variable."""
if csidl_name == "CSIDL_PERSONAL":
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Documents") # noqa: PTH118
@@ -177,6 +216,24 @@ def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None:
if csidl_name == "CSIDL_MYMUSIC":
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Music") # noqa: PTH118
+
+ if csidl_name == "CSIDL_PROGRAMS":
+ return os.path.join( # noqa: PTH118
+ os.path.normpath(os.environ["APPDATA"]),
+ "Microsoft",
+ "Windows",
+ "Start Menu",
+ "Programs",
+ )
+
+ if csidl_name == "CSIDL_COMMON_PROGRAMS":
+ return os.path.join( # noqa: PTH118
+ os.path.normpath(os.environ.get("PROGRAMDATA", os.environ.get("ALLUSERSPROFILE", "C:\\ProgramData"))),
+ "Microsoft",
+ "Windows",
+ "Start Menu",
+ "Programs",
+ )
return None
@@ -190,6 +247,7 @@ def get_win_folder_from_registry(csidl_name: str) -> str:
"""
machine_names = {
"CSIDL_COMMON_APPDATA",
+ "CSIDL_COMMON_PROGRAMS",
}
shell_folder_name = {
"CSIDL_APPDATA": "AppData",
@@ -200,6 +258,8 @@ def get_win_folder_from_registry(csidl_name: str) -> str:
"CSIDL_MYPICTURES": "My Pictures",
"CSIDL_MYVIDEO": "My Video",
"CSIDL_MYMUSIC": "My Music",
+ "CSIDL_PROGRAMS": "Programs",
+ "CSIDL_COMMON_PROGRAMS": "Common Programs",
}.get(csidl_name)
if shell_folder_name is None:
msg = f"Unknown CSIDL name: {csidl_name}"
@@ -226,6 +286,8 @@ _KNOWN_FOLDER_GUIDS: dict[str, str] = {
"CSIDL_MYMUSIC": "{4BD8D571-6D19-48D3-BE97-422220080E43}",
"CSIDL_DOWNLOADS": "{374DE290-123F-4565-9164-39C4925E467B}",
"CSIDL_DESKTOPDIRECTORY": "{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}",
+ "CSIDL_PROGRAMS": "{A77F5D77-2E2B-44C3-A6A2-ABA601054A51}",
+ "CSIDL_COMMON_PROGRAMS": "{0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8}",
}
@@ -271,7 +333,7 @@ def get_win_folder_via_ctypes(csidl_name: str) -> str:
ole32.CLSIDFromString(folder_guid, byref(guid))
path_ptr = wintypes.LPWSTR()
- shell32.SHGetKnownFolderPath(byref(guid), 0, None, byref(path_ptr))
+ shell32.SHGetKnownFolderPath(byref(guid), _KF_FLAG_DONT_VERIFY, None, byref(path_ptr))
result = path_ptr.value
ole32.CoTaskMemFree(path_ptr)
@@ -303,7 +365,21 @@ def _pick_get_win_folder() -> Callable[[str], str]:
return get_win_folder_from_registry
-get_win_folder = lru_cache(maxsize=None)(_pick_get_win_folder())
+_resolve_win_folder = _pick_get_win_folder()
+
+
+def get_win_folder(csidl_name: str) -> str:
+ """
+ Get a Windows folder path, checking for ``WIN_PD_OVERRIDE_*`` environment variable overrides first.
+
+ For example, ``CSIDL_LOCAL_APPDATA`` can be overridden by setting ``WIN_PD_OVERRIDE_LOCAL_APPDATA``.
+
+ """
+ env_var = f"WIN_PD_OVERRIDE_{csidl_name.removeprefix('CSIDL_')}"
+ if override := os.environ.get(env_var, "").strip():
+ return override
+ return _resolve_win_folder(csidl_name)
+
__all__ = [
"Windows",
diff --git a/contrib/python/platformdirs/ya.make b/contrib/python/platformdirs/ya.make
index e763ebaa093..67c5b0e022a 100644
--- a/contrib/python/platformdirs/ya.make
+++ b/contrib/python/platformdirs/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.7.0)
+VERSION(4.9.1)
LICENSE(MIT)
diff --git a/contrib/python/xmltodict/py3/.dist-info/METADATA b/contrib/python/xmltodict/py3/.dist-info/METADATA
index 7eacf2e1faa..00cc7dab64f 100644
--- a/contrib/python/xmltodict/py3/.dist-info/METADATA
+++ b/contrib/python/xmltodict/py3/.dist-info/METADATA
@@ -1,19 +1,11 @@
Metadata-Version: 2.4
Name: xmltodict
-Version: 1.0.2
+Version: 1.0.3
Summary: Makes working with XML feel like you are working with JSON
Author: Martin Blech
-License: Copyright (C) 2012 Martin Blech and individual contributors.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+License-Expression: MIT
Project-URL: Homepage, https://github.com/martinblech/xmltodict
Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
@@ -346,15 +338,15 @@ $ conda install -c conda-forge xmltodict
### RPM-based distro (Fedora, RHEL, …)
-There is an [official Fedora package for xmltodict](https://apps.fedoraproject.org/packages/python-xmltodict).
+There is an [official Fedora package for xmltodict](https://packages.fedoraproject.org/pkgs/python-xmltodict/).
```sh
-$ sudo yum install python-xmltodict
+$ sudo yum install python3-xmltodict
```
### Arch Linux
-There is an [official Arch Linux package for xmltodict](https://www.archlinux.org/packages/community/any/python-xmltodict/).
+There is an [official Arch Linux package for xmltodict](https://archlinux.org/packages/extra/any/python-xmltodict/).
```sh
$ sudo pacman -S python-xmltodict
diff --git a/contrib/python/xmltodict/py3/README.md b/contrib/python/xmltodict/py3/README.md
index b1782a73e07..ff62bf49b61 100644
--- a/contrib/python/xmltodict/py3/README.md
+++ b/contrib/python/xmltodict/py3/README.md
@@ -311,15 +311,15 @@ $ conda install -c conda-forge xmltodict
### RPM-based distro (Fedora, RHEL, …)
-There is an [official Fedora package for xmltodict](https://apps.fedoraproject.org/packages/python-xmltodict).
+There is an [official Fedora package for xmltodict](https://packages.fedoraproject.org/pkgs/python-xmltodict/).
```sh
-$ sudo yum install python-xmltodict
+$ sudo yum install python3-xmltodict
```
### Arch Linux
-There is an [official Arch Linux package for xmltodict](https://www.archlinux.org/packages/community/any/python-xmltodict/).
+There is an [official Arch Linux package for xmltodict](https://archlinux.org/packages/extra/any/python-xmltodict/).
```sh
$ sudo pacman -S python-xmltodict
diff --git a/contrib/python/xmltodict/py3/tests/test_dicttoxml.py b/contrib/python/xmltodict/py3/tests/test_dicttoxml.py
index bd2300aa38e..e67600e27de 100644
--- a/contrib/python/xmltodict/py3/tests/test_dicttoxml.py
+++ b/contrib/python/xmltodict/py3/tests/test_dicttoxml.py
@@ -573,7 +573,7 @@ def test_non_string_text_with_attributes():
assert unparse({"a": {"@param": "flag", "#text": True}}, full_document=False) == '<a param="flag">true</a>'
- assert unparse({"a": {"@param": "test", "#text": None}}, full_document=False) == '<a param="test">None</a>'
+ assert unparse({"a": {"@param": "test", "#text": None}}, full_document=False) == '<a param="test"></a>'
assert unparse({"a": {"@param": "test", "#text": "string"}}, full_document=False) == '<a param="test">string</a>'
@@ -594,3 +594,13 @@ def test_non_string_text_with_attributes():
assert unparse({"a": True}, full_document=False) == unparse({"a": {"#text": True}}, full_document=False)
assert unparse({"a": "hello"}, full_document=False) == unparse({"a": {"#text": "hello"}}, full_document=False)
+ assert unparse({"a": None}, full_document=False) == unparse({"a": {"#text": None}}, full_document=False)
+
+
+def test_none_text_with_short_empty_elements_and_attributes():
+ obj = {"x": {"#text": None, "@pro": None}, "y": None}
+ assert unparse(obj, short_empty_elements=True, full_document=False) == '<x pro=""/><y/>'
+
+
+def test_none_attribute_serializes_as_empty_string():
+ assert unparse({"x": {"@pro": None}}, full_document=False) == '<x pro=""></x>'
diff --git a/contrib/python/xmltodict/py3/xmltodict.py b/contrib/python/xmltodict/py3/xmltodict.py
index 4e97074bae9..6bdf947590a 100644
--- a/contrib/python/xmltodict/py3/xmltodict.py
+++ b/contrib/python/xmltodict/py3/xmltodict.py
@@ -379,6 +379,8 @@ def _convert_value_to_string(value):
if isinstance(value, bool):
return "true" if value else "false"
return str(value)
+
+
def _validate_name(value, kind):
"""Validate an element/attribute name for XML safety.
@@ -491,7 +493,10 @@ def _emit(key, value, content_handler,
children = []
for ik, iv in v.items():
if ik == cdata_key:
- cdata = _convert_value_to_string(iv)
+ if iv is None:
+ cdata = None
+ else:
+ cdata = _convert_value_to_string(iv)
continue
if isinstance(ik, str) and ik.startswith(attr_prefix):
ik = _process_namespace(ik, namespaces, namespace_separator,
@@ -500,9 +505,11 @@ def _emit(key, value, content_handler,
for k, v in iv.items():
_validate_name(k, "attribute")
attr = 'xmlns{}'.format(f':{k}' if k else '')
- attrs[attr] = str(v)
+ attrs[attr] = '' if v is None else str(v)
continue
- if not isinstance(iv, str):
+ if iv is None:
+ iv = ''
+ elif not isinstance(iv, str):
iv = str(iv)
attr_name = ik[len(attr_prefix) :]
_validate_name(attr_name, "attribute")
diff --git a/contrib/python/xmltodict/py3/ya.make b/contrib/python/xmltodict/py3/ya.make
index b27d369dcf0..a26f3f5f3ee 100644
--- a/contrib/python/xmltodict/py3/ya.make
+++ b/contrib/python/xmltodict/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(1.0.2)
+VERSION(1.0.3)
LICENSE(MIT)