Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
1 change: 1 addition & 0 deletions src/docbuild/cli/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
DEFAULT_APP_CONFIG = {
"debug": False,
"role": "production",
"max_workers": "half",
"paths": {
"config_dir": "/etc/docbuild",
"repo_dir": "/data/docserv/repos/permanent-full/",
Expand Down
38 changes: 37 additions & 1 deletion src/docbuild/models/config/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from collections.abc import Sequence # Added Sequence for internal use
from copy import deepcopy
import os
from typing import Any, Literal, Self

from pydantic import BaseModel, ConfigDict, Field, model_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator

from docbuild.config.app import (
CircularReferenceError,
Expand Down Expand Up @@ -188,8 +189,43 @@ class AppConfig(BaseModel):
description="Configuration for the application's logging system.",
)

# Added max_workers with support for ints and descriptive strings
max_workers: int | str = Field(
default="half",
description="Max concurrent workers. Supports integers or 'all', 'all2'/'half'.",
)

model_config = ConfigDict(extra="allow")

@field_validator("max_workers")
@classmethod
def _resolve_worker_count(cls, v: int | str) -> int:
"""Resolve keywords 'all', 'half', 'all2' into concrete integers."""
cpu_count = os.cpu_count() or 1

if isinstance(v, str):
val = v.lower()
if val == "all":
return cpu_count
if val in ("half", "all2"):
return max(1, cpu_count // 2)

# Handle string-digits like "4"
if val.isdigit():
v = int(val)
else:
raise ValueError(
f"Invalid max_workers value: '{v}'. "
"Use an integer, 'all', or 'half'/'all2'."
)
Comment thread
sushant-suse marked this conversation as resolved.

if isinstance(v, int):
if v < 1:
raise ValueError("max_workers must be at least 1")
return v
Comment thread
sushant-suse marked this conversation as resolved.
Outdated

return v

@model_validator(mode="before")
@classmethod
def _resolve_placeholders(cls, data: dict[str, Any]) -> dict[str, Any] | None:
Expand Down
28 changes: 28 additions & 0 deletions tests/models/test_app_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os

import pytest

from docbuild.models.config.app import AppConfig


def test_max_workers_resolution():
cpu = os.cpu_count() or 1
Comment thread
sushant-suse marked this conversation as resolved.
Outdated

# Test keyword "all"
conf_all = AppConfig(max_workers="all")
assert conf_all.max_workers == cpu

# Test keyword "half"
conf_half = AppConfig(max_workers="half")
assert conf_half.max_workers == max(1, cpu // 2)

# Test integer
conf_int = AppConfig(max_workers=4)
assert conf_int.max_workers == 4

def test_max_workers_invalid():
with pytest.raises(ValueError, match="at least 1"):
AppConfig(max_workers=0)

with pytest.raises(ValueError, match="Invalid max_workers"):
AppConfig(max_workers="infinite")
30 changes: 30 additions & 0 deletions tests/models/test_config_workers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os

import pytest

from docbuild.models.config.app import AppConfig


def test_max_workers_resolution_keywords():
cpu = os.cpu_count() or 1
Comment thread
sushant-suse marked this conversation as resolved.
Outdated

# Test 'all'
assert AppConfig(max_workers="all").max_workers == cpu

# Test 'half' and 'all2'
expected_half = max(1, cpu // 2)
assert AppConfig(max_workers="half").max_workers == expected_half
assert AppConfig(max_workers="all2").max_workers == expected_half
Comment thread
sushant-suse marked this conversation as resolved.
Outdated

def test_max_workers_resolution_integers():
# Test strict int
assert AppConfig(max_workers=4).max_workers == 4
# Test string digit
assert AppConfig(max_workers="8").max_workers == 8
Comment thread
sushant-suse marked this conversation as resolved.
Outdated

def test_max_workers_validation_errors():
with pytest.raises(ValueError, match="at least 1"):
AppConfig(max_workers=0)

with pytest.raises(ValueError, match="Invalid max_workers"):
AppConfig(max_workers="unlimited")
Loading