Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
888bec3
refactor(settings): add Inherit sentinel for nested-model cascade def…
henrycgbaker May 20, 2026
4030f98
refactor(annotation): introduce WorkspaceSettings/TaskSettings with c…
henrycgbaker May 20, 2026
4c244e3
test(annotation): migrate fixtures and add cascade propagation tests
henrycgbaker May 20, 2026
e1ae2d8
refactor(settings): align _InheritType style with _UnsetType
henrycgbaker May 20, 2026
6616558
test(annotation): tighten cascade settings tests
henrycgbaker May 20, 2026
e8c67e7
refactor(annotation): rename cascade → inheritance and apply /simplif…
henrycgbaker May 20, 2026
e48ea7d
refactor(annotation): resolve inheritance at read time via resolved_t…
henrycgbaker May 21, 2026
09b1894
feat(annotation): add Locale enum and i18n catalog for Argilla datase…
henrycgbaker May 20, 2026
be150b6
refactor(annotation): align locale tests with resolved_task() and tig…
henrycgbaker May 21, 2026
d7c2bd1
refactor(annotation): open Locale type and move catalogs to YAML
henrycgbaker May 21, 2026
71e1968
refactor(annotation): reuse load_config_file and tighten discard-reas…
henrycgbaker May 21, 2026
83ac35b
feat(annotation): add German locale and discard widget i18n
henrycgbaker May 20, 2026
bf05bbe
refactor(annotation): polish locale structure naming, widget template…
henrycgbaker May 21, 2026
8fb5030
feat(annotation): --locale flag, per-workspace locale, re-import conf…
henrycgbaker May 20, 2026
f0ea488
docs(annotation): name annotation.locale config field in import docst…
henrycgbaker May 21, 2026
10b0eae
refactor(annotation): simplify _detect_dataset_locale via next() and …
henrycgbaker May 21, 2026
5cd013c
refactor(cli): align parse_locale signature with siblings and add unh…
henrycgbaker May 21, 2026
1010838
fixup: adapt parse_locale and locale-mismatch warning to open str Locale
henrycgbaker May 21, 2026
d8a549b
feat(annotation): add --no-calibration and --calibration-partition-se…
henrycgbaker May 21, 2026
7ef68bd
refactor(annotation): use Unset type for CLI calibration overrides
henrycgbaker May 21, 2026
e333b19
docs(annotation): contributor README for adding new locales
henrycgbaker May 21, 2026
3be998c
docs(annotation): rewrite locales README for YAML catalogs and open L…
henrycgbaker May 21, 2026
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
3 changes: 3 additions & 0 deletions src/pragmata/annotation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"ExportResult",
"IaaReport",
"ImportResult",
"Locale",
"SetupResult",
"Task",
"UserSpec",
Expand All @@ -31,6 +32,7 @@
"ExportResult": ("pragmata.core.annotation.export_runner", "ExportResult"),
"IaaReport": ("pragmata.core.schemas.iaa_report", "IaaReport"),
"ImportResult": ("pragmata.api.annotation_import", "ImportResult"),
"Locale": ("pragmata.core.schemas.annotation_task", "Locale"),
"SetupResult": ("pragmata.core.annotation.setup", "SetupResult"),
"Task": ("pragmata.core.schemas.annotation_task", "Task"),
"UserSpec": ("pragmata.core.settings.annotation_settings", "UserSpec"),
Expand Down Expand Up @@ -65,6 +67,7 @@ def __dir__() -> list[str]:
from pragmata.api.annotation_setup import teardown as teardown
from pragmata.core.annotation.export_runner import ExportResult as ExportResult
from pragmata.core.annotation.setup import SetupResult as SetupResult
from pragmata.core.schemas.annotation_task import Locale as Locale
from pragmata.core.schemas.annotation_task import Task as Task
from pragmata.core.schemas.iaa_report import IaaReport as IaaReport
from pragmata.core.settings.annotation_settings import UserSpec as UserSpec
4 changes: 2 additions & 2 deletions src/pragmata/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Internal API layer."""

from pragmata.core.settings.settings_base import UNSET
from pragmata.core.settings.settings_base import UNSET, Unset

from .version import get_version

__all__ = ["get_version", "UNSET"]
__all__ = ["get_version", "UNSET", "Unset"]
22 changes: 22 additions & 0 deletions src/pragmata/api/annotation_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
resolve_import_paths,
)
from pragmata.core.paths.paths import WorkspacePaths
from pragmata.core.schemas.annotation_task import Locale
from pragmata.core.settings.annotation_settings import AnnotationSettings
from pragmata.core.settings.settings_base import UNSET, Unset, load_config_file, resolve_api_key

Expand Down Expand Up @@ -65,6 +66,9 @@ def import_records(
base_dir: str | Path | Unset = UNSET,
config_path: str | Path | Unset = UNSET,
calibration_fraction: float | Unset = UNSET,
calibration_min_submitted: int | None | Unset = UNSET,
calibration_partition_seed: int | Unset = UNSET,
locale: Locale | Unset = UNSET,
) -> ImportResult:
"""Validate and fan out records to per-purpose Argilla annotation datasets.

Expand All @@ -91,6 +95,9 @@ def import_records(
Credential resolution:
- ``api_url``: kwarg > ``ARGILLA_API_URL`` env > config (``argilla.api_url``)
- ``api_key``: kwarg > ``ARGILLA_API_KEY`` env (secrets never live in config)
- ``locale``: kwarg > ``--config`` file (``annotation.locale``) > default
EN. Cascades to per-workspace/per-task overrides defined in the YAML
config.

Args:
records: Input data — list[dict], file path (str/Path), HF Dataset,
Expand All @@ -106,6 +113,18 @@ def import_records(
dataset for this import. Falls through to YAML config and the
built-in default (0.1) when omitted. Set to 0.0 for
production-only batches.
calibration_min_submitted: Deployment-level overlap requirement for
the calibration dataset. ``None`` disables calibration entirely
(must be paired with ``calibration_fraction=0.0``). Inherits to
workspaces/tasks unless they override it.
calibration_partition_seed: Deterministic seed used to assign new
records to calibration vs production buckets. Existing
assignments are locked by the partition manifest; this only
affects records not yet seen.
locale: Deployment-level UI locale for Argilla dataset
titles/questions/guidelines used when auto-creating datasets.
Cascades to workspaces/tasks unless they carve out their own
value in YAML.

Returns:
ImportResult with totals, per-dataset counts, partition counts, and
Expand All @@ -120,6 +139,9 @@ def import_records(
"dataset_id": dataset_id,
"base_dir": base_dir,
"calibration_fraction": calibration_fraction,
"calibration_min_submitted": calibration_min_submitted,
"calibration_partition_seed": calibration_partition_seed,
"locale": locale,
},
)

Expand Down
2 changes: 1 addition & 1 deletion src/pragmata/api/annotation_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def setup(

Datasets are not created here — they are auto-created on import,
scoped by dataset_id. Per-task overlap (production and calibration
``min_submitted``) is configured via ``workspace_dataset_map`` in the
``min_submitted``) is configured via ``workspaces`` in the
YAML config.

Settings are resolved from config file and/or keyword overrides. Omitted
Expand Down
46 changes: 42 additions & 4 deletions src/pragmata/cli/commands/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import typer

from pragmata.api import UNSET
from pragmata.cli.parsing import parse_tasks, parse_user_specs
from pragmata.api import UNSET, Unset
from pragmata.cli.parsing import parse_locale, parse_tasks, parse_user_specs

annotation_app = typer.Typer(help="Annotation pipeline commands.")

Expand Down Expand Up @@ -35,7 +35,7 @@ def setup_command(

Datasets are created automatically on import, not here. Per-task overlap
(production and calibration ``min_submitted``) is configured via
``workspace_dataset_map`` in the YAML config (``--config``).
``workspaces`` in the YAML config (``--config``).
"""
from pragmata import annotation

Expand Down Expand Up @@ -97,6 +97,25 @@ def import_command(
"Falls through to YAML config and built-in default (0.1) when omitted; "
"set to 0.0 for production-only batches.",
),
no_calibration: bool = typer.Option(
False,
"--no-calibration",
help="Disable calibration entirely for this batch: sets calibration_min_submitted=None "
"and calibration_fraction=0.0. Cannot be combined with --calibration-fraction > 0.",
),
calibration_partition_seed: int | None = typer.Option(
None,
"--calibration-partition-seed",
help="Deterministic seed for assigning new records to calibration vs production. "
"Existing assignments are locked by the partition manifest.",
),
locale: str | None = typer.Option(
None,
"--locale",
help="Deployment-level UI locale for Argilla dataset titles/questions/guidelines "
"(en, de). Inherits to workspaces/tasks unless they carve out a value in YAML. "
"Falls back to config, then 'en'.",
),
) -> None:
"""Validate and import records into annotation datasets.

Expand All @@ -106,6 +125,22 @@ def import_command(
"""
from pragmata import annotation

if no_calibration and calibration_fraction is not None and calibration_fraction > 0:
typer.echo(
"Error: --no-calibration cannot be combined with --calibration-fraction > 0.",
err=True,
)
raise typer.Exit(code=2)

resolved_calibration_fraction: float | Unset
resolved_calibration_min_submitted: int | None | Unset
if no_calibration:
resolved_calibration_fraction = 0.0
resolved_calibration_min_submitted = None
else:
resolved_calibration_fraction = UNSET if calibration_fraction is None else calibration_fraction
resolved_calibration_min_submitted = UNSET

result = annotation.import_records(
records,
api_url=UNSET if api_url is None else api_url,
Expand All @@ -114,7 +149,10 @@ def import_command(
dataset_id=UNSET if dataset_id is None else dataset_id,
base_dir=UNSET if base_dir is None else base_dir,
config_path=UNSET if config is None else config,
calibration_fraction=UNSET if calibration_fraction is None else calibration_fraction,
calibration_fraction=resolved_calibration_fraction,
calibration_min_submitted=resolved_calibration_min_submitted,
calibration_partition_seed=UNSET if calibration_partition_seed is None else calibration_partition_seed,
locale=parse_locale(locale) or UNSET,
)
typer.echo(f"Total records: {result.total_records}")
typer.echo(
Expand Down
18 changes: 17 additions & 1 deletion src/pragmata/cli/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pragmata.api import UNSET

if TYPE_CHECKING:
from pragmata.annotation import Task, UserSpec
from pragmata.annotation import Locale, Task, UserSpec


def parse_cli_value(value: str | None) -> Any:
Expand Down Expand Up @@ -51,6 +51,22 @@ def parse_tasks(raw: str | None) -> "list[Task] | None":
return [Task(item.strip()) for item in raw.split(",")]


def parse_locale(raw: str | None) -> "Locale | None":
"""Parse a locale string (e.g. ``en``, ``de``).

Returns None when no locale is supplied, leaving locale selection to
the downstream default. Raises ``ValueError`` if the locale is unknown.
"""
from pragmata.core.annotation.locales.registry import CATALOGS

if raw is None:
return None
locale = raw.strip()
if locale not in CATALOGS:
raise ValueError(f"Unknown locale: {locale!r}. Supported: {sorted(CATALOGS)}")
return locale


def parse_user_specs(path: str | None) -> "list[UserSpec] | None":
"""Load annotator user specs from a JSON file.

Expand Down
Loading