smart-linux-assistant 0.8.1__tar.gz → 0.8.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {smart_linux_assistant-0.8.1/smart_linux_assistant.egg-info → smart_linux_assistant-0.8.2}/PKG-INFO +32 -1
  2. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/README.md +31 -0
  3. smart_linux_assistant-0.8.2/linux_assistant/config/defaults.py +37 -0
  4. smart_linux_assistant-0.8.2/linux_assistant/config/loader.py +64 -0
  5. smart_linux_assistant-0.8.2/linux_assistant/config/models.py +55 -0
  6. smart_linux_assistant-0.8.2/linux_assistant/config/validator.py +154 -0
  7. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/explainer.py +5 -1
  8. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/search.py +5 -3
  9. smart_linux_assistant-0.8.2/linux_assistant/utils/__init__.py +0 -0
  10. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/groq_client.py +6 -6
  11. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/pyproject.toml +1 -1
  12. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2/smart_linux_assistant.egg-info}/PKG-INFO +32 -1
  13. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/SOURCES.txt +6 -0
  14. smart_linux_assistant-0.8.2/tests/test_config_validator.py +57 -0
  15. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/LICENSE +0 -0
  16. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/__init__.py +0 -0
  17. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/cli/__init__.py +0 -0
  18. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/cli/main.py +0 -0
  19. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/config/__init__.py +0 -0
  20. /smart_linux_assistant-0.8.1/linux_assistant/core/__init__.py → /smart_linux_assistant-0.8.2/linux_assistant/config/exceptions.py +0 -0
  21. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/config/settings.py +0 -0
  22. {smart_linux_assistant-0.8.1/linux_assistant/utils → smart_linux_assistant-0.8.2/linux_assistant/core}/__init__.py +0 -0
  23. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/core/safety.py +0 -0
  24. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/exceptions/__init__.py +0 -0
  25. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/exceptions/base.py +0 -0
  26. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/__init__.py +0 -0
  27. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/command_result.py +0 -0
  28. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/history_entry.py +0 -0
  29. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/repositories/__init__.py +0 -0
  30. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/repositories/history_repository.py +0 -0
  31. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/__init__.py +0 -0
  32. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/command_executor.py +0 -0
  33. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/logger.py +0 -0
  34. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/redactor.py +0 -0
  35. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/shell.py +0 -0
  36. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/setup.cfg +0 -0
  37. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/dependency_links.txt +0 -0
  38. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/entry_points.txt +0 -0
  39. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/requires.txt +0 -0
  40. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/top_level.txt +0 -0
  41. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_cli.py +0 -0
  42. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_command_executor.py +0 -0
  43. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_explainer.py +0 -0
  44. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_groq_client.py +0 -0
  45. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_history_repository.py +0 -0
  46. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_redactor.py +0 -0
  47. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_safety.py +0 -0
  48. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_search.py +0 -0
  49. {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_shell.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart-linux-assistant
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: An AI-powered Linux productivity assistant for command analysis, troubleshooting, and knowledge management.
5
5
  Author: Shubham Kumar Jha
6
6
  License: MIT
@@ -100,6 +100,37 @@ This project does not require any environment variables for its core CLI functio
100
100
  | --- | --- | --- |
101
101
  | (none) | No required environment variables for CLI execution | - |
102
102
 
103
+
104
+ ## Configuration
105
+
106
+ Smart Linux Assistant supports a user configuration file. If no configuration file is present, the application automatically falls back to built-in defaults.
107
+
108
+ By default, the application looks for:
109
+
110
+ ```text
111
+ ~/.config/smart-linux-assistant/config.toml
112
+ ```
113
+
114
+ A complete example configuration is available in the repository as:
115
+ ```
116
+ config.toml.example
117
+ ```
118
+ Copy it into your local configuration directory and modify only the values you want to customize.
119
+ Example:
120
+ ```
121
+ mkdir -p ~/.config/smart-linux-assistant
122
+ cp config.toml.example ~/.config/smart-linux-assistant/config.toml
123
+ ```
124
+ Current configurable options include:
125
+
126
+ - AI provider
127
+ - AI model
128
+ - API timeout
129
+ - Retry count
130
+ - Command history settings
131
+ - Logging verbosity
132
+ - Privacy (secret redaction)
133
+
103
134
  ## Usage / API Reference
104
135
 
105
136
  The project exposes the console scripts `smart-linux` and `sla` (configured in `pyproject.toml`).
@@ -73,6 +73,37 @@ This project does not require any environment variables for its core CLI functio
73
73
  | --- | --- | --- |
74
74
  | (none) | No required environment variables for CLI execution | - |
75
75
 
76
+
77
+ ## Configuration
78
+
79
+ Smart Linux Assistant supports a user configuration file. If no configuration file is present, the application automatically falls back to built-in defaults.
80
+
81
+ By default, the application looks for:
82
+
83
+ ```text
84
+ ~/.config/smart-linux-assistant/config.toml
85
+ ```
86
+
87
+ A complete example configuration is available in the repository as:
88
+ ```
89
+ config.toml.example
90
+ ```
91
+ Copy it into your local configuration directory and modify only the values you want to customize.
92
+ Example:
93
+ ```
94
+ mkdir -p ~/.config/smart-linux-assistant
95
+ cp config.toml.example ~/.config/smart-linux-assistant/config.toml
96
+ ```
97
+ Current configurable options include:
98
+
99
+ - AI provider
100
+ - AI model
101
+ - API timeout
102
+ - Retry count
103
+ - Command history settings
104
+ - Logging verbosity
105
+ - Privacy (secret redaction)
106
+
76
107
  ## Usage / API Reference
77
108
 
78
109
  The project exposes the console scripts `smart-linux` and `sla` (configured in `pyproject.toml`).
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from linux_assistant.config.models import (
4
+ AIConfig,
5
+ AppConfig,
6
+ HistoryConfig,
7
+ LoggingConfig,
8
+ PrivacyConfig,
9
+ )
10
+
11
+
12
+ DEFAULT_AI_CONFIG = AIConfig(
13
+ provider="groq",
14
+ model="llama-3.3-70b-versatile",
15
+ timeout_seconds=30.0,
16
+ max_retries=3,
17
+ )
18
+
19
+ DEFAULT_HISTORY_CONFIG = HistoryConfig(
20
+ enabled=True,
21
+ max_entries=5000,
22
+ )
23
+
24
+ DEFAULT_LOGGING_CONFIG = LoggingConfig(
25
+ verbose=False,
26
+ )
27
+
28
+ DEFAULT_PRIVACY_CONFIG = PrivacyConfig(
29
+ redaction_enabled=True,
30
+ )
31
+
32
+ DEFAULT_CONFIG = AppConfig(
33
+ ai=DEFAULT_AI_CONFIG,
34
+ history=DEFAULT_HISTORY_CONFIG,
35
+ logging=DEFAULT_LOGGING_CONFIG,
36
+ privacy=DEFAULT_PRIVACY_CONFIG,
37
+ )
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import tomllib
5
+ from pathlib import Path
6
+
7
+ from linux_assistant.config.defaults import DEFAULT_CONFIG
8
+ from linux_assistant.config.models import AppConfig
9
+ from linux_assistant.config.validator import validate_config
10
+ from linux_assistant.exceptions import ConfigurationError
11
+
12
+ CONFIG_FILE_NAME = "config.toml"
13
+
14
+
15
+ def get_config_path() -> Path:
16
+ """
17
+ Return the location of the user configuration file.
18
+
19
+ The configuration file follows the XDG Base Directory specification.
20
+ If XDG_CONFIG_HOME is not set, ~/.config is used.
21
+ """
22
+ xdg_config_home = os.getenv("XDG_CONFIG_HOME")
23
+
24
+ if xdg_config_home:
25
+ config_home = Path(xdg_config_home)
26
+ else:
27
+ config_home = Path.home() / ".config"
28
+
29
+ return config_home / "smart-linux-assistant" / CONFIG_FILE_NAME
30
+
31
+
32
+ def load_config() -> AppConfig:
33
+ """
34
+ Load the application configuration.
35
+
36
+ Returns the default configuration if no configuration file exists.
37
+
38
+ Raises:
39
+ ConfigurationError:
40
+ If the configuration file cannot be read or contains
41
+ invalid TOML or invalid configuration values.
42
+ """
43
+ config_path = get_config_path()
44
+
45
+ if not config_path.exists():
46
+ return DEFAULT_CONFIG
47
+
48
+ try:
49
+ with config_path.open("rb") as file:
50
+ data = tomllib.load(file)
51
+
52
+ except tomllib.TOMLDecodeError as exc:
53
+ raise ConfigurationError(
54
+ f"Invalid TOML syntax in '{config_path}'."
55
+ ) from exc
56
+
57
+ except OSError as exc:
58
+ raise ConfigurationError(
59
+ f"Unable to read configuration file '{config_path}'."
60
+ ) from exc
61
+
62
+ print(f"Using config: {config_path}")
63
+ print(f"Model: {data['ai']['model']}")
64
+ return validate_config(data)
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class PrivacyConfig:
8
+ """
9
+ Privacy-related configuration.
10
+ """
11
+
12
+ redaction_enabled: bool
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class LoggingConfig:
17
+ """
18
+ Logging-related configuration.
19
+ """
20
+
21
+ verbose: bool
22
+
23
+
24
+ @dataclass(frozen=True, slots=True)
25
+ class HistoryConfig:
26
+ """
27
+ History-related configuration.
28
+ """
29
+
30
+ enabled: bool
31
+ max_entries: int
32
+
33
+
34
+ @dataclass(frozen=True, slots=True)
35
+ class AIConfig:
36
+ """
37
+ AI provider configuration.
38
+ """
39
+
40
+ provider: str
41
+ model: str
42
+ timeout_seconds: float
43
+ max_retries: int
44
+
45
+
46
+ @dataclass(frozen=True, slots=True)
47
+ class AppConfig:
48
+ """
49
+ Root application configuration.
50
+ """
51
+
52
+ ai: AIConfig
53
+ history: HistoryConfig
54
+ logging: LoggingConfig
55
+ privacy: PrivacyConfig
@@ -0,0 +1,154 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from linux_assistant.config.defaults import DEFAULT_CONFIG
6
+ from linux_assistant.config.models import (
7
+ AIConfig,
8
+ AppConfig,
9
+ HistoryConfig,
10
+ LoggingConfig,
11
+ PrivacyConfig,
12
+ )
13
+ from linux_assistant.exceptions import ConfigurationError
14
+
15
+
16
+ def validate_config(data: dict[str, Any]) -> AppConfig:
17
+ """
18
+ Validate and normalize a parsed TOML configuration.
19
+ Missing sections and fields fall back to DEFAULT_CONFIG.
20
+ Invalid field types raise ConfigurationError.
21
+ """
22
+
23
+ if not isinstance(data, dict):
24
+ raise ConfigurationError(
25
+ "Configuration root must be a TOML table."
26
+ )
27
+
28
+ ai = data.get("ai", {})
29
+ history = data.get("history", {})
30
+ logging = data.get("logging", {})
31
+ privacy = data.get("privacy", {})
32
+
33
+ _require_table(ai, "ai")
34
+ _require_table(history, "history")
35
+ _require_table(logging, "logging")
36
+ _require_table(privacy, "privacy")
37
+
38
+ return AppConfig(
39
+ ai=AIConfig(
40
+ provider=_get_str(
41
+ ai,
42
+ "provider",
43
+ DEFAULT_CONFIG.ai.provider,
44
+ ),
45
+ model=_get_str(
46
+ ai,
47
+ "model",
48
+ DEFAULT_CONFIG.ai.model,
49
+ ),
50
+ timeout_seconds=_get_float(
51
+ ai,
52
+ "timeout_seconds",
53
+ DEFAULT_CONFIG.ai.timeout_seconds,
54
+ ),
55
+ max_retries=_get_int(
56
+ ai,
57
+ "max_retries",
58
+ DEFAULT_CONFIG.ai.max_retries,
59
+ ),
60
+ ),
61
+ history=HistoryConfig(
62
+ enabled=_get_bool(
63
+ history,
64
+ "enabled",
65
+ DEFAULT_CONFIG.history.enabled,
66
+ ),
67
+ max_entries=_get_int(
68
+ history,
69
+ "max_entries",
70
+ DEFAULT_CONFIG.history.max_entries,
71
+ ),
72
+ ),
73
+ logging=LoggingConfig(
74
+ verbose=_get_bool(
75
+ logging,
76
+ "verbose",
77
+ DEFAULT_CONFIG.logging.verbose,
78
+ ),
79
+ ),
80
+ privacy=PrivacyConfig(
81
+ redaction_enabled=_get_bool(
82
+ privacy,
83
+ "redaction_enabled",
84
+ DEFAULT_CONFIG.privacy.redaction_enabled,
85
+ ),
86
+ ),
87
+ )
88
+
89
+
90
+ def _require_table(value: Any, section: str) -> None:
91
+ if not isinstance(value, dict):
92
+ raise ConfigurationError(
93
+ f"Configuration section '{section}' must be a TOML table."
94
+ )
95
+
96
+
97
+ def _get_str(
98
+ table: dict[str, Any],
99
+ key: str,
100
+ default: str,
101
+ ) -> str:
102
+ value = table.get(key, default)
103
+
104
+ if not isinstance(value, str):
105
+ raise ConfigurationError(
106
+ f"'{key}' must be a string."
107
+ )
108
+
109
+ return value
110
+
111
+
112
+ def _get_int(
113
+ table: dict[str, Any],
114
+ key: str,
115
+ default: int,
116
+ ) -> int:
117
+ value = table.get(key, default)
118
+
119
+ if not isinstance(value, int):
120
+ raise ConfigurationError(
121
+ f"'{key}' must be an integer."
122
+ )
123
+
124
+ return value
125
+
126
+
127
+ def _get_float(
128
+ table: dict[str, Any],
129
+ key: str,
130
+ default: float,
131
+ ) -> float:
132
+ value = table.get(key, default)
133
+
134
+ if not isinstance(value, (int, float)):
135
+ raise ConfigurationError(
136
+ f"'{key}' must be a number."
137
+ )
138
+
139
+ return float(value)
140
+
141
+
142
+ def _get_bool(
143
+ table: dict[str, Any],
144
+ key: str,
145
+ default: bool,
146
+ ) -> bool:
147
+ value = table.get(key, default)
148
+
149
+ if not isinstance(value, bool):
150
+ raise ConfigurationError(
151
+ f"'{key}' must be a boolean."
152
+ )
153
+
154
+ return value
@@ -4,7 +4,11 @@ AI-powered explanations for Linux commands and error messages.
4
4
 
5
5
  from __future__ import annotations
6
6
  import groq
7
- from linux_assistant.utils.groq_client import GROQ_MODEL, build_groq_client, truncate_for_api
7
+ from linux_assistant.utils.groq_client import (
8
+ GROQ_MODEL,
9
+ build_groq_client,
10
+ truncate_for_api,
11
+ )
8
12
  from linux_assistant.exceptions import MissingAPIKeyError, ServiceError, ValidationError, RateLimitError, HistoryError
9
13
  from linux_assistant.utils.logger import get_logger
10
14
  from linux_assistant.repositories.history_repository import HistoryRepository
@@ -5,10 +5,12 @@ AI-powered natural-language search for Linux commands and tasks.
5
5
  from __future__ import annotations
6
6
  import groq
7
7
  from linux_assistant.exceptions import ServiceError, ValidationError, RateLimitError
8
- from linux_assistant.utils.groq_client import GROQ_MODEL, build_groq_client
8
+ from linux_assistant.utils.groq_client import (
9
+ GROQ_MODEL,
10
+ build_groq_client,
11
+ truncate_for_api,
12
+ )
9
13
  from linux_assistant.utils.logger import get_logger
10
- from linux_assistant.utils.groq_client import GROQ_MODEL, build_groq_client, truncate_for_api
11
-
12
14
  logger = get_logger(__name__)
13
15
 
14
16
  SEARCH_SYSTEM_PROMPT = """You are a Linux command lookup tool operating in a raw terminal. The user will describe a desired action in plain language. Your objective is to provide a concrete, ready-to-run command and a brief explanation.
@@ -5,14 +5,14 @@ Shared Groq client construction for AI-powered services.
5
5
  from __future__ import annotations
6
6
  import os
7
7
  from groq import Groq
8
+ from linux_assistant.config.loader import load_config
8
9
  from linux_assistant.exceptions import MissingAPIKeyError
9
10
 
10
11
  GROQ_API_KEY = "GROQ_API_KEY"
11
- GROQ_MODEL = "llama-3.3-70b-versatile"
12
-
12
+ CONFIG = load_config()
13
+ GROQ_MODEL = CONFIG.ai.model
13
14
  MAX_INPUT_CHARACTERS = 4000
14
- REQUEST_TIMEOUT_SECONDS = 30.0
15
- MAX_RETRIES = 2
15
+
16
16
 
17
17
 
18
18
  def build_groq_client() -> Groq:
@@ -34,8 +34,8 @@ def build_groq_client() -> Groq:
34
34
 
35
35
  return Groq(
36
36
  api_key=api_key,
37
- timeout=REQUEST_TIMEOUT_SECONDS,
38
- max_retries=MAX_RETRIES,
37
+ timeout=CONFIG.ai.timeout_seconds,
38
+ max_retries=CONFIG.ai.max_retries,
39
39
  )
40
40
 
41
41
  def truncate_for_api(text: str, *, keep_end: bool = False) -> str:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "smart-linux-assistant"
7
- version = "0.8.1"
7
+ version = "0.8.2"
8
8
  description = "An AI-powered Linux productivity assistant for command analysis, troubleshooting, and knowledge management."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart-linux-assistant
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: An AI-powered Linux productivity assistant for command analysis, troubleshooting, and knowledge management.
5
5
  Author: Shubham Kumar Jha
6
6
  License: MIT
@@ -100,6 +100,37 @@ This project does not require any environment variables for its core CLI functio
100
100
  | --- | --- | --- |
101
101
  | (none) | No required environment variables for CLI execution | - |
102
102
 
103
+
104
+ ## Configuration
105
+
106
+ Smart Linux Assistant supports a user configuration file. If no configuration file is present, the application automatically falls back to built-in defaults.
107
+
108
+ By default, the application looks for:
109
+
110
+ ```text
111
+ ~/.config/smart-linux-assistant/config.toml
112
+ ```
113
+
114
+ A complete example configuration is available in the repository as:
115
+ ```
116
+ config.toml.example
117
+ ```
118
+ Copy it into your local configuration directory and modify only the values you want to customize.
119
+ Example:
120
+ ```
121
+ mkdir -p ~/.config/smart-linux-assistant
122
+ cp config.toml.example ~/.config/smart-linux-assistant/config.toml
123
+ ```
124
+ Current configurable options include:
125
+
126
+ - AI provider
127
+ - AI model
128
+ - API timeout
129
+ - Retry count
130
+ - Command history settings
131
+ - Logging verbosity
132
+ - Privacy (secret redaction)
133
+
103
134
  ## Usage / API Reference
104
135
 
105
136
  The project exposes the console scripts `smart-linux` and `sla` (configured in `pyproject.toml`).
@@ -5,7 +5,12 @@ linux_assistant/__init__.py
5
5
  linux_assistant/cli/__init__.py
6
6
  linux_assistant/cli/main.py
7
7
  linux_assistant/config/__init__.py
8
+ linux_assistant/config/defaults.py
9
+ linux_assistant/config/exceptions.py
10
+ linux_assistant/config/loader.py
11
+ linux_assistant/config/models.py
8
12
  linux_assistant/config/settings.py
13
+ linux_assistant/config/validator.py
9
14
  linux_assistant/core/__init__.py
10
15
  linux_assistant/core/safety.py
11
16
  linux_assistant/exceptions/__init__.py
@@ -32,6 +37,7 @@ smart_linux_assistant.egg-info/requires.txt
32
37
  smart_linux_assistant.egg-info/top_level.txt
33
38
  tests/test_cli.py
34
39
  tests/test_command_executor.py
40
+ tests/test_config_validator.py
35
41
  tests/test_explainer.py
36
42
  tests/test_groq_client.py
37
43
  tests/test_history_repository.py
@@ -0,0 +1,57 @@
1
+ import pytest
2
+
3
+ from linux_assistant.config.defaults import DEFAULT_CONFIG
4
+ from linux_assistant.config.validator import validate_config
5
+ from linux_assistant.exceptions import ConfigurationError
6
+
7
+
8
+ def test_empty_configuration_returns_defaults() -> None:
9
+ config = validate_config({})
10
+
11
+ assert config == DEFAULT_CONFIG
12
+
13
+
14
+ def test_partial_configuration_overrides_defaults() -> None:
15
+ config = validate_config(
16
+ {
17
+ "logging": {
18
+ "verbose": True,
19
+ }
20
+ }
21
+ )
22
+
23
+ assert config.logging.verbose is True
24
+ assert config.ai == DEFAULT_CONFIG.ai
25
+ assert config.history == DEFAULT_CONFIG.history
26
+ assert config.privacy == DEFAULT_CONFIG.privacy
27
+
28
+
29
+ def test_invalid_boolean_raises_configuration_error() -> None:
30
+ with pytest.raises(ConfigurationError):
31
+ validate_config(
32
+ {
33
+ "logging": {
34
+ "verbose": "yes",
35
+ }
36
+ }
37
+ )
38
+
39
+
40
+ def test_invalid_integer_raises_configuration_error() -> None:
41
+ with pytest.raises(ConfigurationError):
42
+ validate_config(
43
+ {
44
+ "history": {
45
+ "max_entries": "5000",
46
+ }
47
+ }
48
+ )
49
+
50
+
51
+ def test_invalid_section_type_raises_configuration_error() -> None:
52
+ with pytest.raises(ConfigurationError):
53
+ validate_config(
54
+ {
55
+ "history": True,
56
+ }
57
+ )