Compare commits

...
3 Commits
Author SHA1 Message Date
arcanis 6e1567e6db fix tox environments 2026-07-14 16:16:06 +03:00
arcanis 6862d9b9e1 fix docs generation 2026-07-14 15:00:57 +03:00
arcanis 4119a3a36c straight forward conftest 2026-07-14 12:19:04 +03:00
17 changed files with 290 additions and 257 deletions
+1
View File
@@ -3,4 +3,5 @@ addopts = --cov=ahriman --cov-report=term-missing:skip-covered --no-cov-on-fail
asyncio_default_fixture_loop_scope = function
asyncio_mode = auto
pythonpath = tests
resource-path.directory-name-test-resources = ../../tests/testresources
spec_test_format = {result} {docstring_summary}
+157 -5
View File
@@ -1,10 +1,162 @@
from pathlib import Path
import datetime
import pytest
from fixtures import * # pylint: disable=wildcard-import,unused-wildcard-import
from unittest.mock import MagicMock, PropertyMock
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import AUR
from ahriman.core.configuration import Configuration
from ahriman.models.aur_package import AURPackage
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.remote_source import RemoteSource
from ahriman.models.scan_paths import ScanPaths
@pytest.fixture
def resource_path_root() -> Path:
return Path(__file__).resolve().parents[2] / "tests" / "testresources"
def aur_package_akonadi() -> AURPackage:
"""
fixture for AUR package
Returns:
AURPackage: AUR package test instance
"""
return AURPackage(
id=0,
name="akonadi",
package_base_id=0,
package_base="akonadi",
version="21.12.3-2",
description="PIM layer, which provides an asynchronous API to access all kind of PIM data",
num_votes=0,
popularity=0.0,
first_submitted=datetime.datetime.fromtimestamp(0, datetime.UTC),
last_modified=datetime.datetime.fromtimestamp(1646555990.610, datetime.UTC),
url_path="",
url="https://kontact.kde.org",
out_of_date=None,
maintainer="felixonmars",
repository="extra",
depends=[
"libakonadi",
"mariadb",
],
make_depends=[
"boost",
"doxygen",
"extra-cmake-modules",
"kaccounts-integration",
"kitemmodels",
"postgresql",
"qt5-tools",
],
opt_depends=[
"postgresql: PostgreSQL backend",
],
conflicts=[],
provides=[],
license=["LGPL"],
keywords=[],
groups=[],
)
@pytest.fixture
def package_tpacpi_bat_git() -> Package:
"""
git package fixture
Returns:
Package: git package test instance
"""
return Package(
base="tpacpi-bat-git",
version="3.1.r12.g4959b52-1",
remote=RemoteSource(
source=PackageSource.AUR,
git_url=AUR.remote_git_url("tpacpi-bat-git", "aur"),
web_url=AUR.remote_web_url("tpacpi-bat-git"),
path=".",
branch="master",
),
packages={"tpacpi-bat-git": PackageDescription()})
@pytest.fixture
def pacman(configuration: Configuration) -> Pacman:
"""
fixture for pacman wrapper
Args:
configuration(Configuration): configuration fixture
Returns:
Pacman: pacman wrapper test instance
"""
_, repository_id = configuration.check_loaded()
return Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled)
@pytest.fixture
def passwd() -> MagicMock:
"""
get passwd structure for the user
Returns:
MagicMock: passwd structure test instance
"""
passwd = MagicMock()
passwd.pw_dir = "home"
passwd.pw_name = "ahriman"
return passwd
@pytest.fixture
def pyalpm_package_ahriman(aur_package_ahriman: AURPackage) -> MagicMock:
"""
mock object for pyalpm package
Args:
aur_package_ahriman(AURPackage): package fixture
Returns:
MagicMock: pyalpm package mock
"""
mock = MagicMock()
db = type(mock).db = MagicMock()
type(mock).base = PropertyMock(return_value=aur_package_ahriman.package_base)
type(mock).builddate = PropertyMock(
return_value=aur_package_ahriman.last_modified.replace(tzinfo=datetime.timezone.utc).timestamp())
type(mock).conflicts = PropertyMock(return_value=aur_package_ahriman.conflicts)
type(db).name = PropertyMock(return_value="aur")
type(mock).depends = PropertyMock(return_value=aur_package_ahriman.depends)
type(mock).desc = PropertyMock(return_value=aur_package_ahriman.description)
type(mock).licenses = PropertyMock(return_value=aur_package_ahriman.license)
type(mock).makedepends = PropertyMock(return_value=aur_package_ahriman.make_depends)
type(mock).name = PropertyMock(return_value=aur_package_ahriman.name)
type(mock).optdepends = PropertyMock(return_value=aur_package_ahriman.opt_depends)
type(mock).checkdepends = PropertyMock(return_value=aur_package_ahriman.check_depends)
type(mock).packager = PropertyMock(return_value="packager")
type(mock).provides = PropertyMock(return_value=aur_package_ahriman.provides)
type(mock).version = PropertyMock(return_value=aur_package_ahriman.version)
type(mock).url = PropertyMock(return_value=aur_package_ahriman.url)
type(mock).groups = PropertyMock(return_value=aur_package_ahriman.groups)
return mock
@pytest.fixture
def scan_paths(configuration: Configuration) -> ScanPaths:
"""
scan paths fixture
Args:
configuration(Configuration): configuration test instance
Returns:
ScanPaths: scan paths test instance
"""
return ScanPaths(configuration.getlist("build", "scan_paths", fallback=[]))
-10
View File
@@ -1,10 +0,0 @@
from pathlib import Path
import pytest
from fixtures import * # pylint: disable=wildcard-import,unused-wildcard-import
@pytest.fixture
def resource_path_root() -> Path:
return Path(__file__).resolve().parents[2] / "tests" / "testresources"
+13 -5
View File
@@ -1,10 +1,18 @@
from pathlib import Path
import pytest
from fixtures import * # pylint: disable=wildcard-import,unused-wildcard-import
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
@pytest.fixture
def resource_path_root() -> Path:
return Path(__file__).resolve().parents[2] / "tests" / "testresources"
def auth(configuration: Configuration) -> Auth:
"""
auth provider fixture
Args:
configuration(Configuration): configuration fixture
Returns:
Auth: auth service instance
"""
return Auth(configuration)
+1 -166
View File
@@ -7,12 +7,10 @@ from pathlib import Path
from pytest_mock import MockerFixture
from sqlite3 import Cursor
from typing import Any, TypeVar
from unittest.mock import MagicMock, PropertyMock
from unittest.mock import MagicMock
from ahriman.application.ahriman import _parser
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import AUR
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.database.migrations import Migrations
@@ -30,12 +28,10 @@ from ahriman.models.migration import Migration
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.remote_source import RemoteSource
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths
from ahriman.models.result import Result
from ahriman.models.scan_paths import ScanPaths
from ahriman.models.user import User
from ahriman.models.user_access import UserAccess
@@ -243,68 +239,6 @@ def aur_package_ahriman() -> AURPackage:
)
@pytest.fixture
def aur_package_akonadi() -> AURPackage:
"""
fixture for AUR package
Returns:
AURPackage: AUR package test instance
"""
return AURPackage(
id=0,
name="akonadi",
package_base_id=0,
package_base="akonadi",
version="21.12.3-2",
description="PIM layer, which provides an asynchronous API to access all kind of PIM data",
num_votes=0,
popularity=0.0,
first_submitted=datetime.datetime.fromtimestamp(0, datetime.UTC),
last_modified=datetime.datetime.fromtimestamp(1646555990.610, datetime.UTC),
url_path="",
url="https://kontact.kde.org",
out_of_date=None,
maintainer="felixonmars",
repository="extra",
depends=[
"libakonadi",
"mariadb",
],
make_depends=[
"boost",
"doxygen",
"extra-cmake-modules",
"kaccounts-integration",
"kitemmodels",
"postgresql",
"qt5-tools",
],
opt_depends=[
"postgresql: PostgreSQL backend",
],
conflicts=[],
provides=[],
license=["LGPL"],
keywords=[],
groups=[],
)
@pytest.fixture
def auth(configuration: Configuration) -> Auth:
"""
auth provider fixture
Args:
configuration(Configuration): configuration fixture
Returns:
Auth: auth service instance
"""
return Auth(configuration)
@pytest.fixture
def configuration(repository_id: RepositoryId, tmp_path: Path, resource_path_root: Path) -> Configuration:
"""
@@ -453,27 +387,6 @@ def package_python_schedule(
packages=packages)
@pytest.fixture
def package_tpacpi_bat_git() -> Package:
"""
git package fixture
Returns:
Package: git package test instance
"""
return Package(
base="tpacpi-bat-git",
version="3.1.r12.g4959b52-1",
remote=RemoteSource(
source=PackageSource.AUR,
git_url=AUR.remote_git_url("tpacpi-bat-git", "aur"),
web_url=AUR.remote_web_url("tpacpi-bat-git"),
path=".",
branch="master",
),
packages={"tpacpi-bat-git": PackageDescription()})
@pytest.fixture
def package_description_ahriman() -> PackageDescription:
"""
@@ -575,70 +488,6 @@ def package_description_python2_schedule() -> PackageDescription:
)
@pytest.fixture
def pacman(configuration: Configuration) -> Pacman:
"""
fixture for pacman wrapper
Args:
configuration(Configuration): configuration fixture
Returns:
Pacman: pacman wrapper test instance
"""
_, repository_id = configuration.check_loaded()
return Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled)
@pytest.fixture
def passwd() -> MagicMock:
"""
get passwd structure for the user
Returns:
MagicMock: passwd structure test instance
"""
passwd = MagicMock()
passwd.pw_dir = "home"
passwd.pw_name = "ahriman"
return passwd
@pytest.fixture
def pyalpm_package_ahriman(aur_package_ahriman: AURPackage) -> MagicMock:
"""
mock object for pyalpm package
Args:
aur_package_ahriman(AURPackage): package fixture
Returns:
MagicMock: pyalpm package mock
"""
mock = MagicMock()
db = type(mock).db = MagicMock()
type(mock).base = PropertyMock(return_value=aur_package_ahriman.package_base)
type(mock).builddate = PropertyMock(
return_value=aur_package_ahriman.last_modified.replace(tzinfo=datetime.timezone.utc).timestamp())
type(mock).conflicts = PropertyMock(return_value=aur_package_ahriman.conflicts)
type(db).name = PropertyMock(return_value="aur")
type(mock).depends = PropertyMock(return_value=aur_package_ahriman.depends)
type(mock).desc = PropertyMock(return_value=aur_package_ahriman.description)
type(mock).licenses = PropertyMock(return_value=aur_package_ahriman.license)
type(mock).makedepends = PropertyMock(return_value=aur_package_ahriman.make_depends)
type(mock).name = PropertyMock(return_value=aur_package_ahriman.name)
type(mock).optdepends = PropertyMock(return_value=aur_package_ahriman.opt_depends)
type(mock).checkdepends = PropertyMock(return_value=aur_package_ahriman.check_depends)
type(mock).packager = PropertyMock(return_value="packager")
type(mock).provides = PropertyMock(return_value=aur_package_ahriman.provides)
type(mock).version = PropertyMock(return_value=aur_package_ahriman.version)
type(mock).url = PropertyMock(return_value=aur_package_ahriman.url)
type(mock).groups = PropertyMock(return_value=aur_package_ahriman.groups)
return mock
@pytest.fixture
def remote_source() -> RemoteSource:
"""
@@ -715,20 +564,6 @@ def result(package_ahriman: Package) -> Result:
return result
@pytest.fixture
def scan_paths(configuration: Configuration) -> ScanPaths:
"""
scan paths fixture
Args:
configuration(Configuration): configuration test instance
Returns:
ScanPaths: scan paths test instance
"""
return ScanPaths(configuration.getlist("build", "scan_paths", fallback=[]))
@pytest.fixture
def spawner(configuration: Configuration) -> Spawn:
"""
+2 -2
View File
@@ -68,8 +68,8 @@ COPY --chown=build . "/home/build/ahriman"
## create package archive and install it
RUN cd "/home/build/ahriman" && \
tox -e archive && \
cp ./dist/*.tar.gz "package/archlinux" && \
cd "package/archlinux" && \
cp ./dist/*.tar.gz "archlinux" && \
cd "archlinux" && \
runuser -u build -- makepkg --noconfirm --skipchecksums && \
cd / && rm -r "/home/build/ahriman"
+9 -16
View File
@@ -1,6 +1,15 @@
ahriman.application.handlers package
====================================
Subpackages
-----------
.. toctree::
:maxdepth: 4
ahriman.application.handlers.triggers_support
ahriman.application.handlers.web
Submodules
----------
@@ -268,14 +277,6 @@ ahriman.application.handlers.triggers module
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.triggers\_support module
-----------------------------------------------------
.. automodule:: ahriman.application.handlers.triggers_support
:members:
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.unsafe\_commands module
----------------------------------------------------
@@ -316,14 +317,6 @@ ahriman.application.handlers.versions module
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.web module
---------------------------------------
.. automodule:: ahriman.application.handlers.web
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
@@ -0,0 +1,21 @@
ahriman.application.handlers.triggers\_support package
======================================================
Submodules
----------
ahriman.application.handlers.triggers\_support.triggers\_support module
-----------------------------------------------------------------------
.. automodule:: ahriman.application.handlers.triggers_support.triggers_support
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ahriman.application.handlers.triggers_support
:members:
:no-undoc-members:
:show-inheritance:
+21
View File
@@ -0,0 +1,21 @@
ahriman.application.handlers.web package
========================================
Submodules
----------
ahriman.application.handlers.web.web module
-------------------------------------------
.. automodule:: ahriman.application.handlers.web.web
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ahriman.application.handlers.web
:members:
:no-undoc-members:
:show-inheritance:
+22 -17
View File
@@ -1,19 +1,19 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --group pyproject.toml:docs --extra s3 --extra validator --extra web --output-file docs/requirements.txt pyproject.toml
# uv pip compile --group pyproject.toml:docs --no-emit-package ahriman-core --no-emit-package ahriman-triggers --no-emit-package ahriman-web --output-file docs/requirements.txt pyproject.toml
aiohappyeyeballs==2.6.1
# via aiohttp
aiohttp==3.11.18
# via
# ahriman (pyproject.toml)
# ahriman-web
# aiohttp-cors
# aiohttp-jinja2
# aiohttp-sse
aiohttp-cors==0.8.1
# via ahriman (pyproject.toml)
# via ahriman-web
aiohttp-jinja2==1.6
# via ahriman (pyproject.toml)
# via ahriman-web
aiohttp-sse==2.2.0
# via ahriman (pyproject.toml)
# via ahriman-web
aiosignal==1.3.2
# via aiohttp
alabaster==1.0.0
@@ -25,15 +25,15 @@ attrs==25.3.0
babel==2.17.0
# via sphinx
bcrypt==4.3.0
# via ahriman (pyproject.toml)
boto3==1.38.11
# via ahriman (pyproject.toml)
botocore==1.38.11
# via ahriman-core
boto3==1.43.47
# via ahriman-core
botocore==1.43.47
# via
# boto3
# s3transfer
cerberus==1.3.7
# via ahriman (pyproject.toml)
cerberus==1.3.8
# via ahriman-core
certifi==2025.4.26
# via requests
charset-normalizer==3.4.2
@@ -44,7 +44,7 @@ docutils==0.21.2
# sphinx-argparse
# sphinx-rtd-theme
filelock==3.24.0
# via ahriman (pyproject.toml)
# via ahriman-core
frozenlist==1.6.0
# via
# aiohttp
@@ -56,12 +56,12 @@ idna==3.10
imagesize==1.4.1
# via sphinx
inflection==0.5.1
# via ahriman (pyproject.toml)
# via ahriman-core
jinja2==3.1.6
# via
# aiohttp-jinja2
# sphinx
jmespath==1.0.1
jmespath==1.1.0
# via
# boto3
# botocore
@@ -80,18 +80,18 @@ propcache==0.3.1
pydeps==3.0.1
# via ahriman (pyproject.toml:docs)
pyelftools==0.32
# via ahriman (pyproject.toml)
# via ahriman-core
pygments==2.19.1
# via sphinx
python-dateutil==2.9.0.post0
# via botocore
requests==2.32.3
# via
# ahriman (pyproject.toml)
# ahriman-core
# sphinx
roman-numerals-py==3.1.0
# via sphinx
s3transfer==0.12.0
s3transfer==0.19.1
# via boto3
shtab==1.7.2
# via ahriman (pyproject.toml:docs)
@@ -131,3 +131,8 @@ urllib3==2.4.0
# requests
yarl==1.20.0
# via aiohttp
# The following packages were excluded from the output:
# ahriman-core
# ahriman-triggers
# ahriman-web
+13
View File
@@ -36,6 +36,7 @@ check = [
"pylint",
]
docs = [
"ahriman-core[s3,validator]",
"Sphinx",
"argparse-manpage",
"pydeps",
@@ -81,3 +82,15 @@ workspace.members = [
[tool.hatch.version]
path = "ahriman-core/src/ahriman/__init__.py"
[tool.uv.sources]
ahriman-core = {workspace = true}
ahriman-triggers = {workspace = true}
ahriman-web = {workspace = true}
[tool.uv.workspace]
members = [
"ahriman-core",
"ahriman-triggers",
"ahriman-web",
]
+10 -13
View File
@@ -91,7 +91,6 @@ deps = [
{ replace = "ref", of = ["project", "extras"], extend = true },
]
pip_pre = true
skip_install = true
set_env.CFLAGS = "-Wno-unterminated-string-initialization"
set_env.MYPYPATH = "ahriman-core/src:ahriman-triggers/src:ahriman-web/src"
commands = [
@@ -160,9 +159,8 @@ deps = [
{ replace = "ref", of = ["project", "extras"], extend = true },
"uv",
]
dynamic_version = "{[project]name}.__version__"
dynamic_version = "{[project]name}"
pip_pre = true
set_env.PYTHONPATH = "ahriman-core/src:ahriman-triggers/src:ahriman-web/src"
set_env.SPHINX_APIDOC_OPTIONS = "members,no-undoc-members,show-inheritance"
commands = [
[
@@ -190,16 +188,14 @@ commands = [
"--dot-output", "{tox_root}/docs/_static/architecture.dot",
"--no-output",
"--show-dot",
"ahriman-core/src/ahriman",
"{envsitepackagesdir}/{[project]name}",
],
[
"sphinx-apidoc",
"--force",
"--no-toc",
"--output-dir", "docs",
"ahriman-core/src",
"ahriman-triggers/src",
"ahriman-web/src",
"{envsitepackagesdir}/{[project]name}",
],
# compile list of dependencies for rtd.io
[
@@ -207,9 +203,9 @@ commands = [
"pip",
"compile",
"--group", "pyproject.toml:docs",
"--extra", "s3",
"--extra", "validator",
"--extra", "web",
"--no-emit-package", "ahriman-core",
"--no-emit-package", "ahriman-triggers",
"--no-emit-package", "ahriman-web",
"--output-file", "docs/requirements.txt",
"--quiet",
"pyproject.toml",
@@ -246,7 +242,7 @@ commands = [
"sphinx-build",
"--builder", "html",
"--fail-on-warning",
"--jobs", "auto",
"--jobs", "1",
"--write-all",
"docs",
"{envtmpdir}/html",
@@ -268,9 +264,9 @@ commands = [
[
"git",
"add",
"archlinux/PKGBUILD",
"docs/_static/architecture.dot",
"frontend/package.json",
"package/archlinux/PKGBUILD",
"ahriman-core/package/share/man/man1/ahriman.1",
"ahriman-core/package/share/bash-completion/completions/_ahriman",
"ahriman-core/package/share/zsh/site-functions/_ahriman",
@@ -327,6 +323,7 @@ allowlist_externals = [
deps = [
"packaging",
]
skip_install = true
commands = [
# check if version is set and validate it
[
@@ -349,6 +346,6 @@ commands = [
"sed",
"--in-place",
"s/pkgver=.*/pkgver={posargs}/",
"package/archlinux/PKGBUILD",
"archlinux/PKGBUILD",
],
]
+20 -23
View File
@@ -17,8 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import importlib
import sys
from importlib.metadata import Distribution, PackageNotFoundError
from tox.config.sets import EnvConfigSet
from tox.plugin import impl
@@ -26,32 +25,34 @@ from tox.session.state import State
from tox.tox_env.api import ToxEnv
def _extract_version(env_conf: EnvConfigSet, python_path: str | None = None) -> dict[str, str]:
def _extract_version(tox_env: ToxEnv) -> dict[str, str]:
"""
extract version dynamically and set VERSION environment variable
Args:
env_conf(EnvConfigSet): the core configuration object
python_path(str | None): python path variable if available
tox_env(ToxEnv): tox environment containing the installed package
Returns:
dict[str, str]: environment variables which must be inserted
Raises:
PackageNotFoundError: no installed distribution has been found
"""
import_path = env_conf["dynamic_version"]
if not import_path:
distribution = tox_env.conf["dynamic_version"]
if not distribution:
return {}
if python_path is not None:
sys.path.append(python_path)
installed = next(
(
package for package in Distribution.discover(path=[str(tox_env.env_site_package_dir())])
if package.name == distribution
),
None,
)
if installed is None:
raise PackageNotFoundError(distribution)
module_name, variable_name = import_path.rsplit(".", maxsplit=1)
module = importlib.import_module(module_name)
version = getattr(module, variable_name)
# reset import paths
sys.path.pop()
return {"VERSION": version}
return {"VERSION": installed.version}
@impl
@@ -70,7 +71,7 @@ def tox_add_env_config(env_conf: EnvConfigSet, state: State) -> None:
keys=["dynamic_version"],
of_type=str,
default="",
desc="import path for the version variable",
desc="distribution name used to populate the VERSION environment variable",
)
@@ -82,8 +83,4 @@ def tox_before_run_commands(tox_env: ToxEnv) -> None:
Args:
tox_env(ToxEnv): the tox environment being executed
"""
env_conf = tox_env.conf
set_env = env_conf["set_env"]
python_path = set_env.load("PYTHONPATH") if "PYTHONPATH" in set_env else None
set_env.update(_extract_version(env_conf, python_path))
tox_env.conf["set_env"].update(_extract_version(tox_env))