Coverage for src / local_deep_research / config / paths.py: 84%
60 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
1"""
2Centralized path configuration for Local Deep Research.
3Handles database location using platformdirs for proper user data storage.
4"""
6import hashlib
7import os
8from pathlib import Path
10import platformdirs
11from loguru import logger
14def get_data_directory() -> Path:
15 """
16 Get the appropriate data directory for storing application data.
17 Uses platformdirs to get platform-specific user data directory.
19 Environment variable:
20 LDR_DATA_DIR: Override the default data directory location.
21 All subdirectories (research_outputs, cache, logs, database)
22 will be created under this directory.
24 Returns:
25 Path to data directory
26 """
27 # Check for explicit override via environment variable
28 custom_path = os.getenv("LDR_DATA_DIR")
29 if custom_path:
30 data_dir = Path(custom_path)
31 logger.debug(
32 f"Using custom data directory from LDR_DATA_DIR: {data_dir}"
33 )
34 return data_dir
36 # Use platformdirs for platform-specific user data directory
37 # Windows: C:\Users\Username\AppData\Local\local-deep-research
38 # macOS: ~/Library/Application Support/local-deep-research
39 # Linux: ~/.local/share/local-deep-research
40 data_dir = Path(platformdirs.user_data_dir("local-deep-research"))
41 # Log only the directory pattern, not the full path which may contain username
42 logger.debug(
43 f"Using platformdirs data directory pattern: .../{data_dir.name}"
44 )
46 return data_dir
49def get_research_outputs_directory() -> Path:
50 """
51 Get the directory for storing research outputs (reports, etc.).
53 Returns:
54 Path to research outputs directory
55 """
56 # Use subdirectory of main data directory
57 data_dir = get_data_directory()
58 outputs_dir = data_dir / "research_outputs"
59 outputs_dir.mkdir(parents=True, exist_ok=True)
61 logger.debug(f"Using research outputs directory: {outputs_dir}")
62 return outputs_dir
65def get_cache_directory() -> Path:
66 """
67 Get the directory for storing cache files (search cache, etc.).
69 Returns:
70 Path to cache directory
71 """
72 # Use subdirectory of main data directory
73 data_dir = get_data_directory()
74 cache_dir = data_dir / "cache"
75 cache_dir.mkdir(parents=True, exist_ok=True)
77 logger.debug(f"Using cache directory: {cache_dir}")
78 return cache_dir
81def get_logs_directory() -> Path:
82 """
83 Get the directory for storing log files.
85 Returns:
86 Path to logs directory
87 """
88 # Use subdirectory of main data directory
89 data_dir = get_data_directory()
90 logs_dir = data_dir / "logs"
91 logs_dir.mkdir(parents=True, exist_ok=True)
93 logger.debug(f"Using logs directory: {logs_dir}")
94 return logs_dir
97def get_encrypted_database_path() -> Path:
98 """Get the path to the encrypted databases directory.
100 Returns:
101 Path to the encrypted databases directory
102 """
103 data_dir = get_data_directory()
104 encrypted_db_path = data_dir / "encrypted_databases"
105 encrypted_db_path.mkdir(parents=True, exist_ok=True)
106 return encrypted_db_path
109def get_user_database_filename(username: str) -> str:
110 """Get the database filename for a specific user.
112 Args:
113 username: The username to generate a filename for
115 Returns:
116 The database filename (not full path) for the user
117 """
118 # Use username hash to avoid filesystem issues with special characters
119 username_hash = hashlib.sha256(username.encode()).hexdigest()[:16]
120 return f"ldr_user_{username_hash}.db"
123def get_library_directory() -> Path:
124 """
125 Get the directory for storing library files (documents, PDFs, etc.).
127 Returns:
128 Path to library directory
129 """
130 # Use subdirectory of main data directory
131 data_dir = get_data_directory()
132 library_dir = data_dir / "library"
133 library_dir.mkdir(parents=True, exist_ok=True)
135 logger.debug(f"Using library directory: {library_dir}")
136 return library_dir
139def get_config_directory() -> Path:
140 """
141 Get the directory for storing configuration files.
143 Returns:
144 Path to config directory
145 """
146 # Use subdirectory of main data directory
147 data_dir = get_data_directory()
148 config_dir = data_dir / "config"
149 config_dir.mkdir(parents=True, exist_ok=True)
151 logger.debug(f"Using config directory: {config_dir}")
152 return config_dir
155def get_models_directory() -> Path:
156 """
157 Get the directory for storing downloaded models.
159 Returns:
160 Path to models directory
161 """
162 # Use subdirectory of main data directory
163 data_dir = get_data_directory()
164 models_dir = data_dir / "models"
165 models_dir.mkdir(parents=True, exist_ok=True)
167 logger.debug(f"Using models directory: {models_dir}")
168 return models_dir
171# Convenience functions for backward compatibility
172def get_data_dir() -> str:
173 """Get data directory as string for backward compatibility."""
174 return str(get_data_directory())