mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
feat: allow to use simplified keys for context
Initial implementation requires explicit context key name to be set. Though it is still useful sometimes (e.g. if there should be two variables with the same type), in the most used scenarios internally only type is required. This commit extends set and get methods to allow to construct ContextKey from type directly Also it breaks old keys, since - in order to reduce amount of possible mistakes - internal classes uses this generation method
This commit is contained in:
parent
c74cd68ad6
commit
ac19c407d3
@ -38,12 +38,12 @@ class _Context:
|
||||
"""
|
||||
self._content: dict[str, Any] = {}
|
||||
|
||||
def get(self, key: ContextKey[T]) -> T:
|
||||
def get(self, key: ContextKey[T] | type[T]) -> T:
|
||||
"""
|
||||
get value for the specified key
|
||||
|
||||
Args:
|
||||
key(ContextKey[T]): context key name
|
||||
key(ContextKey[T] | type[T]): context key name
|
||||
|
||||
Returns:
|
||||
T: value associated with the key
|
||||
@ -52,29 +52,37 @@ class _Context:
|
||||
KeyError: in case if the specified context variable was not found
|
||||
ValueError: in case if type of value is not an instance of specified return type
|
||||
"""
|
||||
if not isinstance(key, ContextKey):
|
||||
key = ContextKey.from_type(key)
|
||||
|
||||
if key.key not in self._content:
|
||||
raise KeyError(key.key)
|
||||
value = self._content[key.key]
|
||||
if not isinstance(value, key.return_type):
|
||||
raise ValueError(f"Value {value} is not an instance of {key.return_type}")
|
||||
|
||||
return value
|
||||
|
||||
def set(self, key: ContextKey[T], value: T) -> None:
|
||||
def set(self, key: ContextKey[T] | type[T], value: T) -> None:
|
||||
"""
|
||||
set value for the specified key
|
||||
|
||||
Args:
|
||||
key(ContextKey[T]): context key name
|
||||
key(ContextKey[T] | type[T]): context key name
|
||||
value(T): context value associated with the specified key
|
||||
|
||||
Raises:
|
||||
KeyError: in case if the specified context variable already exists
|
||||
ValueError: in case if type of value is not an instance of specified return type
|
||||
"""
|
||||
if not isinstance(key, ContextKey):
|
||||
key = ContextKey.from_type(key)
|
||||
|
||||
if key.key in self._content:
|
||||
raise KeyError(key.key)
|
||||
if not isinstance(value, key.return_type):
|
||||
raise ValueError(f"Value {value} is not an instance of {key.return_type}")
|
||||
|
||||
self._content[key.key] = value
|
||||
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
|
@ -22,7 +22,6 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.gitremote.remote_push import RemotePush
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
@ -111,7 +110,7 @@ class RemotePushTrigger(Trigger):
|
||||
GitRemoteError: if database is not set in context
|
||||
"""
|
||||
ctx = context.get()
|
||||
database = ctx.get(ContextKey("database", SQLite))
|
||||
database = ctx.get(SQLite)
|
||||
|
||||
for target in self.targets:
|
||||
section, _ = self.configuration.gettype(
|
||||
|
@ -26,7 +26,6 @@ from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository.executor import Executor
|
||||
from ahriman.core.repository.update_handler import UpdateHandler
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
@ -89,11 +88,11 @@ class Repository(Executor, UpdateHandler):
|
||||
# directly without loader
|
||||
ctx = _Context()
|
||||
|
||||
ctx.set(ContextKey("database", SQLite), self.database)
|
||||
ctx.set(ContextKey("configuration", Configuration), self.configuration)
|
||||
ctx.set(ContextKey("pacman", Pacman), self.pacman)
|
||||
ctx.set(ContextKey("sign", GPG), self.sign)
|
||||
ctx.set(SQLite, self.database)
|
||||
ctx.set(Configuration, self.configuration)
|
||||
ctx.set(Pacman, self.pacman)
|
||||
ctx.set(GPG, self.sign)
|
||||
|
||||
ctx.set(ContextKey("repository", type(self)), self)
|
||||
ctx.set(type(self), self)
|
||||
|
||||
context.set(ctx)
|
||||
|
@ -24,7 +24,6 @@ from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.core.support.package_creator import PackageCreator
|
||||
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
@ -134,8 +133,8 @@ class KeyringTrigger(Trigger):
|
||||
trigger action which will be called at the start of the application
|
||||
"""
|
||||
ctx = context.get()
|
||||
sign = ctx.get(ContextKey("sign", GPG))
|
||||
database = ctx.get(ContextKey("database", SQLite))
|
||||
sign = ctx.get(GPG)
|
||||
database = ctx.get(SQLite)
|
||||
|
||||
for target in self.targets:
|
||||
generator = KeyringGenerator(database, sign, self.repository_id, self.configuration, target)
|
||||
|
@ -25,7 +25,6 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
@ -65,7 +64,7 @@ class PackageCreator:
|
||||
|
||||
# register package
|
||||
ctx = context.get()
|
||||
database: SQLite = ctx.get(ContextKey("database", SQLite))
|
||||
database = ctx.get(SQLite)
|
||||
_, repository_id = self.configuration.check_loaded()
|
||||
package = Package.from_build(local_path, repository_id.architecture, None)
|
||||
database.package_update(package, BuildStatus())
|
||||
|
@ -18,7 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from dataclasses import dataclass
|
||||
from typing import Generic, TypeVar
|
||||
from typing import Generic, Self, TypeVar
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
@ -35,3 +35,16 @@ class ContextKey(Generic[T]):
|
||||
"""
|
||||
key: str
|
||||
return_type: type[T]
|
||||
|
||||
@classmethod
|
||||
def from_type(cls, return_type: type[T]) -> Self:
|
||||
"""
|
||||
construct key from type
|
||||
|
||||
Args:
|
||||
return_type(type[T]): return type used for the specified context key
|
||||
|
||||
Returns:
|
||||
Self: context key with autogenerated
|
||||
"""
|
||||
return cls(return_type.__name__, return_type)
|
||||
|
@ -3,7 +3,6 @@ from pytest_mock import MockerFixture
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.gitremote import RemotePushTrigger
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
@ -30,5 +29,5 @@ def test_on_result(configuration: Configuration, result: Result, package_ahriman
|
||||
trigger = RemotePushTrigger(repository_id, configuration)
|
||||
|
||||
trigger.on_result(result, [package_ahriman])
|
||||
database_mock.assert_called_once_with(ContextKey("database", SQLite))
|
||||
database_mock.assert_called_once_with(SQLite)
|
||||
run_mock.assert_called_once_with(result)
|
||||
|
@ -6,7 +6,6 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.models.context_key import ContextKey
|
||||
|
||||
|
||||
def test_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None:
|
||||
@ -29,9 +28,9 @@ def test_set_context(configuration: Configuration, database: SQLite, mocker: Moc
|
||||
|
||||
instance = Repository.load(repository_id, configuration, database, report=False)
|
||||
set_mock.assert_has_calls([
|
||||
MockCall(ContextKey("database", SQLite), instance.database),
|
||||
MockCall(ContextKey("configuration", Configuration), instance.configuration),
|
||||
MockCall(ContextKey("pacman", Pacman), instance.pacman),
|
||||
MockCall(ContextKey("sign", GPG), instance.sign),
|
||||
MockCall(ContextKey("repository", Repository), instance),
|
||||
MockCall(SQLite, instance.database),
|
||||
MockCall(Configuration, instance.configuration),
|
||||
MockCall(Pacman, instance.pacman),
|
||||
MockCall(GPG, instance.sign),
|
||||
MockCall(Repository, instance),
|
||||
])
|
||||
|
@ -5,7 +5,6 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.core.support import KeyringTrigger
|
||||
from ahriman.models.context_key import ContextKey
|
||||
|
||||
|
||||
def test_configuration_sections(configuration: Configuration) -> None:
|
||||
@ -29,5 +28,5 @@ def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
|
||||
trigger = KeyringTrigger(repository_id, configuration)
|
||||
trigger.on_start()
|
||||
context_mock.assert_has_calls([MockCall(ContextKey("sign", GPG)), MockCall(ContextKey("database", SQLite))])
|
||||
context_mock.assert_has_calls([MockCall(GPG), MockCall(SQLite)])
|
||||
run_mock.assert_called_once_with()
|
||||
|
@ -4,7 +4,6 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.support.package_creator import PackageCreator
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_description import PackageDescription
|
||||
from ahriman.models.package_source import PackageSource
|
||||
@ -38,5 +37,5 @@ def test_run(package_creator: PackageCreator, database: SQLite, mocker: MockerFi
|
||||
init_mock.assert_called_once_with(local_path)
|
||||
|
||||
package_mock.assert_called_once_with(local_path, "x86_64", None)
|
||||
database_mock.assert_called_once_with(ContextKey("database", SQLite))
|
||||
database_mock.assert_called_once_with(SQLite)
|
||||
insert_mock.assert_called_once_with(package, pytest.helpers.anyvar(int))
|
||||
|
@ -15,6 +15,18 @@ def test_get_set() -> None:
|
||||
assert ctx.get(key) == value
|
||||
|
||||
|
||||
def test_get_set_type() -> None:
|
||||
"""
|
||||
must set and get variable by type
|
||||
"""
|
||||
key, value = int, 42
|
||||
ctx = _Context()
|
||||
|
||||
ctx.set(key, value)
|
||||
assert ctx.get(key) == value
|
||||
assert ctx.get(ContextKey.from_type(int)) == value
|
||||
|
||||
|
||||
def test_get_key_exception() -> None:
|
||||
"""
|
||||
must raise KeyError in case if key was not found
|
||||
|
@ -0,0 +1,9 @@
|
||||
from ahriman.models.context_key import ContextKey
|
||||
|
||||
|
||||
def test_from_type() -> None:
|
||||
"""
|
||||
must construct key from type
|
||||
"""
|
||||
assert ContextKey.from_type(int) == ContextKey("int", int)
|
||||
assert ContextKey.from_type(ContextKey) == ContextKey("ContextKey", ContextKey)
|
Loading…
Reference in New Issue
Block a user