diff --git a/nonebot_plugin_localstore/__init__.py b/nonebot_plugin_localstore/__init__.py index e50b50c..9f08b76 100644 --- a/nonebot_plugin_localstore/__init__.py +++ b/nonebot_plugin_localstore/__init__.py @@ -4,10 +4,10 @@ from nonebot import get_plugin_config from nonebot.plugin import Plugin, PluginMetadata, get_plugin_by_module_name +from nonestorage import user_cache_dir, user_config_dir, user_data_dir from typing_extensions import ParamSpec from .config import Config -from .data_source import user_cache_dir, user_config_dir, user_data_dir __plugin_meta__ = PluginMetadata( name="本地数据存储", diff --git a/nonebot_plugin_localstore/data_source.py b/nonebot_plugin_localstore/data_source.py deleted file mode 100644 index 1cedb14..0000000 --- a/nonebot_plugin_localstore/data_source.py +++ /dev/null @@ -1,146 +0,0 @@ -import os -import sys -from pathlib import Path -from typing import Literal - -WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt") - - -def user_cache_dir(appname: str) -> Path: - r""" - Return full path to the user-specific cache dir for this application. - "appname" is the name of application. - Typical user cache directories are: - macOS: ~/Library/Caches/ - Unix: ~/.cache/ (XDG default) - Windows: C:\Users\\AppData\Local\\Cache - On Windows the only suggestion in the MSDN docs is that local settings go - in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the - non-roaming app data dir (the default returned by `user_data_dir`). Apps - typically put cache data somewhere *under* the given dir here. Some - examples: - ...\Mozilla\Firefox\Profiles\\Cache - ...\Acme\SuperApp\Cache\1.0 - OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. - """ - if WINDOWS: - return _get_win_folder("CSIDL_LOCAL_APPDATA") / appname / "Cache" - elif sys.platform == "darwin": - return Path("~/Library/Caches").expanduser() / appname - else: - return Path(os.getenv("XDG_CACHE_HOME", "~/.cache")).expanduser() / appname - - -def user_data_dir(appname: str, roaming: bool = False) -> Path: - r""" - Return full path to the user-specific data dir for this application. - "appname" is the name of application. - If None, just the system directory is returned. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - - for a discussion of issues. - Typical user data directories are: - macOS: ~/Library/Application Support/ - Unix: ~/.local/share/ # or in - $XDG_DATA_HOME, if defined - Win XP (not roaming): C:\Documents and Settings\\ ... - ...Application Data\ - Win XP (roaming): C:\Documents and Settings\\Local ... - ...Settings\Application Data\ - Win 7 (not roaming): C:\Users\\AppData\Local\ - Win 7 (roaming): C:\Users\\AppData\Roaming\ - For Unix, we follow the XDG spec and support $XDG_DATA_HOME. - That means, by default "~/.local/share/". - """ - if WINDOWS: - const = "CSIDL_APPDATA" if roaming else "CSIDL_LOCAL_APPDATA" - return Path(_get_win_folder(const)) / appname - elif sys.platform == "darwin": - return Path("~/Library/Application Support/").expanduser() / appname - else: - return Path(os.getenv("XDG_DATA_HOME", "~/.local/share")).expanduser() / appname - - -def user_config_dir(appname: str, roaming: bool = True) -> Path: - """Return full path to the user-specific config dir for this application. - "appname" is the name of application. - If None, just the system directory is returned. - "roaming" (boolean, default True) can be set False to not use the - Windows roaming appdata directory. That means that for users on a - Windows network setup for roaming profiles, this user data will be - sync'd on login. See - - for a discussion of issues. - Typical user data directories are: - macOS: same as user_data_dir - Unix: ~/.config/ - Win *: same as user_data_dir - For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. - That means, by default "~/.config/". - """ - if WINDOWS: - return user_data_dir(appname, roaming=roaming) - elif sys.platform == "darwin": - return user_data_dir(appname) - else: - return Path(os.getenv("XDG_CONFIG_HOME", "~/.config")).expanduser() / appname - - -# -- Windows support functions -- -def _get_win_folder_from_registry( - csidl_name: Literal["CSIDL_APPDATA", "CSIDL_COMMON_APPDATA", "CSIDL_LOCAL_APPDATA"], -) -> Path: - """ - This is a fallback technique at best. I'm not sure if using the - registry for this guarantees us the correct answer for all CSIDL_* - names. - """ - import winreg - - shell_folder_name = { - "CSIDL_APPDATA": "AppData", - "CSIDL_COMMON_APPDATA": "Common AppData", - "CSIDL_LOCAL_APPDATA": "Local AppData", - }[csidl_name] - - key = winreg.OpenKey( - winreg.HKEY_CURRENT_USER, - r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", - ) - directory, _type = winreg.QueryValueEx(key, shell_folder_name) - return Path(directory) - - -def _get_win_folder_with_ctypes( - csidl_name: Literal["CSIDL_APPDATA", "CSIDL_COMMON_APPDATA", "CSIDL_LOCAL_APPDATA"], -) -> Path: - csidl_const = { - "CSIDL_APPDATA": 26, - "CSIDL_COMMON_APPDATA": 35, - "CSIDL_LOCAL_APPDATA": 28, - }[csidl_name] - - buf = ctypes.create_unicode_buffer(1024) - ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) - - # Downgrade to short path name if have highbit chars. See - # . - has_high_char = any(ord(c) > 255 for c in buf) - if has_high_char: - buf2 = ctypes.create_unicode_buffer(1024) - if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): - buf = buf2 - - return Path(buf.value) - - -if WINDOWS: - try: - import ctypes - - _get_win_folder = _get_win_folder_with_ctypes - except ImportError: - _get_win_folder = _get_win_folder_from_registry diff --git a/poetry.lock b/poetry.lock index 37cbd85..a1381c2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -591,6 +591,17 @@ files = [ [package.dependencies] prompt-toolkit = ">=3.0.19,<4.0.0" +[[package]] +name = "nonestorage" +version = "0.1.0" +description = "Simple library that provides local storage folder detect" +optional = false +python-versions = "<4.0,>=3.9" +files = [ + {file = "nonestorage-0.1.0-py3-none-any.whl", hash = "sha256:35811adf67c680c272bcb71fa9d6c3613cc2d1bb79f5bfc7d83c4412a79537cb"}, + {file = "nonestorage-0.1.0.tar.gz", hash = "sha256:818232236455c79cabbb69e716f73aa1b9c21d579f1c1fcbdba273b60bac72d9"}, +] + [[package]] name = "packaging" version = "24.2" @@ -1307,4 +1318,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a120300e8f0cd347d471ebdc074339b2626fd803354252589444e6d6b62e28a6" +content-hash = "cc0fcf0f731a41d68dc39300cc50ff6682b5cf4ec0964c556d461d13fa90bde3" diff --git a/pyproject.toml b/pyproject.toml index b935966..c103feb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ keywords = ["nonebot2", "qq", "plugin"] [tool.poetry.dependencies] python = "^3.9" nonebot2 = "^2.3.0" +nonestorage = "^0.1.0" typing-extensions = "^4.0.0" pydantic = ">=1.10.0,<3.0.0,!=2.5.0,!=2.5.1"