Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b611820
Added functionality to clean-up stale (e.g. longer than 30 days) Obje…
skulpok-akamai Oct 28, 2025
bea9b7d
Code review changes: removed functionality to set the cleanup options…
skulpok-akamai Nov 26, 2025
faa7876
Code review changes: reverting package version restriction
skulpok-akamai Nov 27, 2025
9344290
Code review changes: improving cleanup info message
skulpok-akamai Nov 27, 2025
6a2c9fb
Code review changes: tests improved and minor corrections
skulpok-akamai Nov 27, 2025
20ab1cd
Update tests/integration/obj/test_obj_plugin.py
skulpok-akamai Nov 27, 2025
3f9286a
Code review changes: tests updated
skulpok-akamai Nov 27, 2025
63644a5
Update linodecli/plugins/obj/__init__.py
skulpok-akamai Nov 27, 2025
408e171
Code review changes: small improvements suggested by Copilot
skulpok-akamai Nov 27, 2025
9e2e2c9
Update linodecli/configuration/config.py
skulpok-akamai Nov 27, 2025
fb071f6
Update linodecli/configuration/config.py
skulpok-akamai Nov 27, 2025
a1ac3e1
Update tests/integration/obj/test_obj_plugin.py
skulpok-akamai Nov 27, 2025
9f64ccb
Update tests/integration/obj/test_obj_plugin.py
skulpok-akamai Nov 27, 2025
0a7f4db
Update tests/integration/obj/test_obj_plugin.py
skulpok-akamai Nov 27, 2025
df1209f
Code review changes: test updated
skulpok-akamai Nov 27, 2025
9eb85c8
Migrate integration tests to unit tests
lgarber-akamai Dec 11, 2025
3f9ccc4
fix imports
lgarber-akamai Dec 11, 2025
732d773
fix python 3.10 compat
lgarber-akamai Dec 11, 2025
9eb1f51
fix lint
lgarber-akamai Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@ py-version=3.9
# Discover python modules and packages in the file system subtree.
recursive=no

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is longer supported in pylint causing an error


# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
Expand Down
69 changes: 57 additions & 12 deletions linodecli/configuration/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import argparse
import os
import sys
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Type, TypeVar, cast

from linodecli.exit_codes import ExitCodes

Expand All @@ -27,6 +27,8 @@

ENV_TOKEN_NAME = "LINODE_CLI_TOKEN"

T = TypeVar("T")


class CLIConfig:
"""
Expand Down Expand Up @@ -216,15 +218,12 @@ def plugin_set_value(self, key: str, value: Any):
:param value: The value to set for this key
:type value: any
"""
if self.running_plugin is None:
raise RuntimeError(
"No running plugin to retrieve configuration for!"
)

username = self.username or self.default_username()
self.config.set(username, f"plugin-{self.running_plugin}-{key}", value)
self.config.set(username, self._get_plugin_key(key), value)

def plugin_get_value(self, key: str) -> Optional[Any]:
def plugin_get_value(
self, key: str, default: Optional[T] = None, value_type: Type[T] = str
) -> Optional[T]:
"""
Retrieves and returns a config value previously set for a plugin. Your
plugin should have set this value in the past. If this value does not
Expand All @@ -235,18 +234,54 @@ def plugin_get_value(self, key: str) -> Optional[Any]:
:param key: The key of the value to return
:type key: str

:param default: The default value to return if the key is not set
:type default: T

:param value_type: The type to which the value should be cast
:type value_type: Type[T]

:returns: The value for this plugin for this key, or None if not set
:rtype: any
"""
username = self.username or self.default_username() or "DEFAULT"
value = self.config.get(
username, self._get_plugin_key(key), fallback=None
)
if value is None:
return default

if value_type == str:
return value

if value_type == bool:
bool_value = self.parse_boolean(value)
return bool_value if bool_value is not None else default

try:
return cast(T, value_type(value))
except (ValueError, TypeError):
print(
f"Could not cast config value {value} to {value_type}.",
file=sys.stderr,
)
return default

def plugin_remove_option(self, key: str):
"""
Removes a plugin configuration option.

:param key: The key of the option to remove
"""
username = self.username or self.default_username()
self.config.remove_option(username, self._get_plugin_key(key))

def _get_plugin_key(self, key: str) -> str:
if self.running_plugin is None:
raise RuntimeError(
"No running plugin to retrieve configuration for!"
)

username = self.username or self.default_username() or "DEFAULT"
full_key = f"plugin-{self.running_plugin}-{key}"

return self.config.get(username, full_key, fallback=None)
return f"plugin-{self.running_plugin}-{key}"

# TODO: this is more of an argparsing function than it is a config function
# might be better to move this to argparsing during refactor and just have
Expand Down Expand Up @@ -654,3 +689,13 @@ def get_custom_aliases(self) -> Dict[str, str]:
if (self.config.has_section("custom_aliases"))
else {}
)

def parse_boolean(self, value: str) -> Optional[bool]:
"""
Parses a string config value into a boolean. Returns None if the value
cannot be parsed as a boolean.

:param value: The string value to parse.
:return: The parsed boolean value.
"""
return self.config.BOOLEAN_STATES.get(value.lower(), None)
Loading
Loading