Metadata-Version: 2.4
Name: eu5miner
Version: 0.8.0
Summary: Text-first parsing and modding support library for Europa Universalis V data files, with optional MCP server and Kivy desktop GUI
Author: Val G and GitHub Copilot
License: MIT
Requires-Python: >=3.12
Provides-Extra: all
Requires-Dist: kivy<3,>=2.3; extra == 'all'
Requires-Dist: mcp<2,>=1.28.1; extra == 'all'
Provides-Extra: dev
Requires-Dist: mypy>=1.15.0; extra == 'dev'
Requires-Dist: pytest-timeout>=2.3.1; extra == 'dev'
Requires-Dist: pytest>=9.1.1; extra == 'dev'
Requires-Dist: ruff>=0.15.21; extra == 'dev'
Provides-Extra: gui
Requires-Dist: kivy<3,>=2.3; extra == 'gui'
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.28.1; extra == 'mcp'
Description-Content-Type: text/markdown

# EU5Miner (core)

The core library of the [EU5Miner umbrella](https://github.com/Vality/EU5Miner). See the umbrella [README.md](../../README.md) for install and layout.

EU5Miner is a text-first Python library for reading, indexing, and planning edits to Europa Universalis V data and mod files.

This is an unofficial community project. It is not affiliated with, endorsed by, or sponsored by Paradox Interactive or the Europa Universalis V development team.

The repository and published package do not include game assets. Real-file validation and many install-backed workflows expect a locally available EU5 installation.

Release `0.8.0` is the current umbrella release; the previous `0.7.x` and `0.6.x` lines stay supported.

The current release focuses on the major moddable text-based file families:

- Clausewitz-style script text used in `common`, `events`, `setup`, and `map_data`
- GUI script
- Localization YAML
- JSON metadata
- Semicolon-delimited CSV

The project is intentionally test-heavy. Core functionality is validated against representative real EU5 install files so later parser work is anchored in observed game behavior instead of assumptions.

## Module paths and extras

This package is the single `eu5miner` distribution. It exposes three Python modules:

- `eu5miner` — core library and CLI (always available).
- `eu5miner.mcp` — MCP server (requires the `[mcp]` extra).
- `eu5miner.gui` — Kivy desktop UI (requires the `[gui]` extra).

Without the matching extra, importing `eu5miner.mcp` or `eu5miner.gui` raises an `ImportError` directing you to install the extra.

## Status

The `0.8.x` line is published from this umbrella as a single `eu5miner` wheel with optional extras (`pip install eu5miner[mcp]`, `eu5miner[gui]`, `eu5miner[all]`). The MCP server and GUI are submodules inside the unified package rather than separate distributions.

Compared with `0.5.0`, the `0.6.x` line expanded the stable read-only inspection seam with initial entity browsing for economy, diplomacy, government, religion, and map while keeping the public API deliberately curated.

- The root package, grouped domain packages, `eu5miner.inspection`, and the `eu5miner.mods` facade are intended for real use.
- The CLI is intended as a thin convenience surface over the same library APIs.
- Additional helper layers and future editing surfaces are still expected to evolve before `1.0`.
- API coverage is intentionally incomplete relative to the full game data surface; missing families and API adjustments should still be expected during the preview line.

In practice, this release is suitable for install inspection, virtual filesystem queries, representative parsing, typed domain reads, and the current mod update planning and application workflow. It is not yet a promise that every exported helper will remain unchanged across future minor releases.

## Install

```bash
pip install eu5miner
```

Or with the optional surfaces:

```bash
pip install eu5miner[mcp]   # adds eu5miner.mcp
pip install eu5miner[gui]   # adds eu5miner.gui
pip install eu5miner[all]
```

Python 3.12 and [uv](https://docs.astral.sh/uv/) are required for development.

## Development

Within the umbrella workspace:

```bash
cd EU5Miner
uv sync --extra=dev
cd packages/core
uv run pytest
uv run ruff check .
uv run mypy src
uv build
```

The repo is stored under OneDrive. The Windows setup script at `scripts/setup-centralized-uv.ps1` points `UV_PROJECT_ENVIRONMENT` at `%USERPROFILE%\.venvs\EU5Miner`, sets `UV_LINK_MODE=copy` for OneDrive-safe `uv` operations, and runs `uv sync --extra dev` there.

Run the broader optional sweep explicitly when you want wider install-backed coverage:

```bash
uv run python -m pytest -m broad
```

## CLI

The project ships a thin CLI:

```powershell
eu5miner inspect-install
eu5miner list-systems
eu5miner list-files --phase in_game --subpath gui --limit 10
eu5miner analyze-script --representative scripted_trigger
eu5miner report-system --install-root C:\EU5 --system economy
eu5miner report-system --install-root C:\EU5 --system diplomacy
eu5miner plan-mod-update --install-root C:\EU5 --mod-root C:\mods\my_mod --phase in_game --subtree common/buildings --content-root C:\work\content
eu5miner apply-mod-update --install-root C:\EU5 --mod-root C:\mods\my_mod --phase in_game --subtree common/buildings --content-root C:\work\content
```

These seven commands and their documented arguments are the intended thin CLI contract. Higher-level automation should prefer the library facades in `eu5miner.inspection` and `eu5miner.mods` rather than depending on internal CLI helpers.

`list-systems` and `report-system` provide install-backed summaries for the major connected systems currently implemented in the library: `economy`, `diplomacy`, `government`, `religion`, `interface`, and `map`.

The mod workflow commands print a structured report to stdout, `note:` advisories for planned metadata actions such as `replace_path` additions, and `warning:` diagnostics for intended outputs that will still be shadowed by later sources.

## Library

The root package intentionally stays narrow. It exposes install discovery, VFS primitives, and the public mod workflow facade:

```python
from pathlib import Path

from eu5miner import ContentPhase, GameInstall, VirtualFilesystem, plan_mod_update

install = GameInstall.discover(r"C:\Program Files (x86)\Steam\steamapps\common\Europa Universalis V")
vfs = VirtualFilesystem.from_install(install)

merged = vfs.get_merged_file(ContentPhase.IN_GAME, Path("gui") / "agenda_view.gui")
assert merged is not None

update = plan_mod_update(
    vfs,
    "my_mod",
    ContentPhase.IN_GAME,
    Path("common") / "buildings",
    intended_relative_paths=(Path("common") / "buildings" / "a.txt",),
    content_by_relative_path={Path("common") / "buildings" / "a.txt": "building = {}\n"},
)
```

The root package does not also re-export install inspection helpers or domain parsing helpers. Keep those imports explicit so downstream code can depend on the intended stable seams.

For downstream GUI and MCP consumers that need a stable read-only seam for install discovery, high-level system summaries, and initial entity browsing, use `eu5miner.inspection` instead of reaching into CLI helpers:

```python
from eu5miner import GameInstall
from eu5miner.inspection import (
    get_system_entity,
    format_install_summary,
    format_system_report,
    get_system_report,
    inspect_install,
    list_entity_systems,
    list_system_entities,
    list_supported_systems,
)

summary = inspect_install(r"C:\Program Files (x86)\Steam\steamapps\common\Europa Universalis V")
print(format_install_summary(summary))

systems = list_supported_systems()
economy_report = get_system_report(
    GameInstall.discover(summary.root),
    "economy",
)
print(format_system_report(economy_report))

entity_systems = list_entity_systems()
economy_entities = list_system_entities(
    GameInstall.discover(summary.root),
    "economy",
)
iron = get_system_entity(
    GameInstall.discover(summary.root),
    "economy",
    "iron",
)
```

This inspection facade is the stable public entrypoint for install summaries, available system listing, install-backed system report retrieval, and a deliberately narrow entity-browsing seam. The current browseable subset is intentionally limited to one primary entity family per system: `economy` goods, `diplomacy` casus belli, `government` government types, `religion` religions, and `map` linked locations. That keeps the preview API useful for GUI and MCP read-only flows without overcommitting to a generic graph API across every catalog family yet.

Repeated inspection entity queries are cached process-locally per install, system, and mod-root context. If a mutating workflow can change inspection results, invalidate the affected system entries with `eu5miner.inspection.invalidate_system_entity_cache(...)` or otherwise refresh the inspection cache state before querying again.

For domain adapters and higher-level helpers, prefer grouped package entrypoints when you are working within one concept area:

```python
from eu5miner.domains.diplomacy import (
    build_diplomacy_graph_catalog,
    build_war_flow_catalog,
    parse_casus_belli_document,
    parse_country_interaction_document,
    parse_peace_treaty_document,
    parse_subject_type_document,
    parse_wargoal_document,
)
from eu5miner.domains.economy import (
    build_market_catalog,
    parse_goods_document,
    parse_price_document,
)
from eu5miner.domains.government import build_government_catalog, parse_government_type_document
from eu5miner.domains.localization import build_localization_bundle
from eu5miner.domains.map import build_linked_location_document, parse_default_map_document
from eu5miner.domains.religion import build_religion_catalog, parse_religion_document
from eu5miner.domains.units import parse_unit_category_document

casus_belli_document = parse_casus_belli_document(
    "sample_cb = { war_goal_type = superiority }\n"
)
wargoal_document = parse_wargoal_document(
    "superiority = { type = superiority attacker = { conquer_cost = 1 } }\n"
)
peace_treaty_document = parse_peace_treaty_document(
    "peace_example = { effect = { make_subject_of = { type = subject_type:sample_subject } } }\n"
)
subject_type_document = parse_subject_type_document(
    "sample_subject = { level = 1 allow_subjects = no }\n"
)
country_interaction_document = parse_country_interaction_document(
    "sample_country_interaction = { type = diplomacy }\n"
)

war_catalog = build_war_flow_catalog(
    casus_belli_documents=(casus_belli_document,),
    wargoal_documents=(wargoal_document,),
    peace_treaty_documents=(peace_treaty_document,),
    subject_type_documents=(subject_type_document,),
)
diplomacy_catalog = build_diplomacy_graph_catalog(
    casus_belli_documents=(casus_belli_document,),
    wargoal_documents=(wargoal_document,),
    peace_treaty_documents=(peace_treaty_document,),
    subject_type_documents=(subject_type_document,),
    country_interaction_documents=(country_interaction_document,),
)

goods_document = parse_goods_document("iron = { method = mining category = raw_material }\n")
price_document = parse_price_document("build_road = { gold = 10 }\n")
market_catalog = build_market_catalog(
    goods_documents=(goods_document,),
    price_documents=(price_document,),
)

government_type_document = parse_government_type_document(
    "monarchy = { heir_selection = cognatic government_power = legitimacy }\n"
)
government_catalog = build_government_catalog(
    government_type_documents=(government_type_document,),
)

religion_document = parse_religion_document("example_faith = { group = abrahamic }\n")
religion_catalog = build_religion_catalog(religion_documents=(religion_document,))

default_map_document = parse_default_map_document('setup = "definitions.txt"\n')
localization_bundle = build_localization_bundle(
    (("sample.yml", 'l_english:\nSAMPLE_KEY: "Sample"\n'),)
)
unit_category_document = parse_unit_category_document(
    "sample_category = { is_army = yes startup_amount = 1 }\n"
)
```

For mod update workflows in the preview release, `eu5miner.mods` remains the stable higher-level seam, while the CLI stays a thin wrapper over the same plan/apply/report operations.

The built-in `apply_mod_update(...)` flow already invalidates matching inspection entity caches when the planned update still carries install-backed context. Lower-level direct write helpers such as `materialize_targeted_mod_emission(...)` remain inspection-agnostic on purpose, so callers using those helpers directly must own any required inspection cache refresh or invalidation themselves.

The broad `eu5miner.domains` convenience export remains available for callers that genuinely want one import hub across many domains, but grouped packages are the preferred stable seam when the concept area is clear. Avoid reaching into internal implementation modules such as `eu5miner.domains.diplomacy.casus_belli` or `eu5miner.domains.map.map_text` from downstream code.

## Testing

The default baseline keeps `uv run pytest` warning-free even when plugin-specific pytest options are unavailable.

When the development environment includes `pytest-timeout` via `uv sync --extra dev`, the suite also applies a global per-test timeout and preserves the per-test `@pytest.mark.timeout(...)` overrides used by parser-sensitive tests.

## Configuration

The test suite and install-discovery helpers use this precedence for the game install path:

1. `EU5_INSTALL_DIR`
2. The default Steam install path on Windows

## Documentation

- Umbrella planning entrypoint: [ROADMAP.md](../../ROADMAP.md)
- Umbrella release history: [CHANGELOG.md](../../CHANGELOG.md)
- Migration notes for the workspace consolidation: [RENAMING.md](../../RENAMING.md)
- Execution-ready work packages: [documents/specs/README.md](../../documents/core/README.md)
- Architecture constraints and layering rules: [documents/architecture.md](../../documents/architecture.md)
- Developer environment notes for the OneDrive/`uv` workflow: [documents/development-environment.md](../../documents/development-environment.md)
- `1.0` boundary and blocker set: [documents/v1-scope.md](../../documents/v1-scope.md) and [documents/v1-release-readiness.md](../../documents/v1-release-readiness.md)
