Skip to content
Merged
2 changes: 0 additions & 2 deletions src/bom_lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
)
from .types import (
Inventory,
InventoryType,
PartData,
ProjectSlot,
StatsDict,
Expand All @@ -48,7 +47,6 @@

__all__ = [
# types
"InventoryType",
"StatsDict",
"create_empty_inventory",
"PartData",
Expand Down
6 changes: 3 additions & 3 deletions src/bom_lib/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
parse_pedalpcb_pdf,
parse_with_verification,
)
from src.bom_lib.types import InventoryType, StatsDict, create_empty_inventory
from src.bom_lib.types import Inventory, StatsDict, create_empty_inventory

logger = logging.getLogger(__name__)


def _process_pdf_content(
content: bytes, source_name: str
) -> tuple[InventoryType, StatsDict]:
) -> tuple[Inventory, StatsDict]:
"""Helper to handle binary PDF content via temp file."""
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
tmp.write(content)
Expand All @@ -40,7 +40,7 @@ def _process_pdf_content(

def process_input_data(
method: str, data: Any, source_name: str
) -> tuple[InventoryType, StatsDict, str | None, bytes | None]:
) -> tuple[Inventory, StatsDict, str | None, bytes | None]:
"""
Unified handler for processing Text, File, and URL inputs.

Expand Down
14 changes: 7 additions & 7 deletions src/bom_lib/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
- Renaming sources/projects.
"""

from src.bom_lib.types import InventoryType, PartData
from src.bom_lib.types import Inventory, PartData
from src.bom_lib.utils import parse_value_to_float


def calculate_net_needs(bom: InventoryType, stock: InventoryType) -> InventoryType:
def calculate_net_needs(bom: Inventory, stock: Inventory) -> Inventory:
"""
Calculates the deficit between Required parts (BOM) and Owned parts (Stock).

Expand All @@ -21,10 +21,10 @@ def calculate_net_needs(bom: InventoryType, stock: InventoryType) -> InventoryTy
stock: The user's current inventory.

Returns:
A new InventoryType containing ONLY the items that need to be purchased.
A new Inventory dictionary containing ONLY the items that need to be purchased.
Quantities are set to `max(0, required - owned)`.
"""
net_inv = InventoryType()
net_inv = Inventory()

for key, data in bom.items():
gross_needed = data["qty"]
Expand All @@ -43,7 +43,7 @@ def calculate_net_needs(bom: InventoryType, stock: InventoryType) -> InventoryTy
return net_inv


def sort_inventory(inventory: InventoryType) -> list[tuple[str, PartData]]:
def sort_inventory(inventory: Inventory) -> list[tuple[str, PartData]]:
"""
Sorts the inventory for display.

Expand Down Expand Up @@ -93,7 +93,7 @@ def sort_key(item: tuple[str, PartData]) -> tuple[int, float, str]:


def rename_source_in_inventory(
inventory: InventoryType, old_name: str, new_name: str
inventory: Inventory, old_name: str, new_name: str
) -> None:
"""
Updates the source key in the inventory (e.g., renaming a project).
Expand All @@ -111,7 +111,7 @@ def rename_source_in_inventory(
part["sources"][new_name] = part["sources"].pop(old_name)


def serialize_inventory(inventory: InventoryType) -> str:
def serialize_inventory(inventory: Inventory) -> str:
"""
Converts the inventory dict back into the standardized text format.
e.g. {'Resistors | 10k': refs=['R1', 'R2']} -> "R1 10k\\nR2 10k"
Expand Down
22 changes: 10 additions & 12 deletions src/bom_lib/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import src.bom_lib.constants as C
from src.bom_lib.classifier import categorize_part, normalize_value_by_category
from src.bom_lib.types import InventoryType, StatsDict, create_empty_inventory
from src.bom_lib.types import Inventory, StatsDict, create_empty_inventory
from src.bom_lib.utils import expand_refs

# Initialize Logger
Expand All @@ -35,7 +35,7 @@


def ingest_bom_line(
inventory: InventoryType,
inventory: Inventory,
source: str,
ref_raw: str,
val_raw: str,
Expand Down Expand Up @@ -90,7 +90,7 @@ def ingest_bom_line(

def parse_with_verification(
bom_list: list[str], source_name: str = "Manual Input"
) -> tuple[InventoryType, StatsDict]:
) -> tuple[Inventory, StatsDict]:
"""
Parses a list of raw text strings (Manual BOM Input).

Expand Down Expand Up @@ -167,7 +167,7 @@ def parse_with_verification(
return inventory, stats


def parse_csv_bom(filepath: str, source_name: str) -> tuple[InventoryType, StatsDict]:
def parse_csv_bom(filepath: str, source_name: str) -> tuple[Inventory, StatsDict]:
"""
Parses a CSV BOM file.

Expand Down Expand Up @@ -229,7 +229,7 @@ def parse_csv_bom(filepath: str, source_name: str) -> tuple[InventoryType, Stats
return inventory, stats


def parse_user_inventory(filepath: str) -> InventoryType:
def parse_user_inventory(filepath: str) -> Inventory:
"""
Parses a user's stock CSV.

Expand All @@ -240,9 +240,9 @@ def parse_user_inventory(filepath: str) -> InventoryType:
filepath: Path to the user inventory CSV.

Returns:
A populated InventoryType dictionary.
A populated Inventory dictionary.
"""
stock: InventoryType = create_empty_inventory()
stock: Inventory = create_empty_inventory()

with open(filepath, encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
Expand Down Expand Up @@ -270,7 +270,7 @@ def parse_user_inventory(filepath: str) -> InventoryType:

def _parse_via_tables(
pages_data: list[dict[str, Any]],
inventory: InventoryType,
inventory: Inventory,
source_name: str,
stats: StatsDict,
) -> None:
Expand Down Expand Up @@ -338,7 +338,7 @@ def _parse_via_tables(

def _parse_via_regex(
pages_data: list[dict[str, Any]],
inventory: InventoryType,
inventory: Inventory,
source_name: str,
stats: StatsDict,
) -> None:
Expand Down Expand Up @@ -448,9 +448,7 @@ def _parse_via_regex(
stats["parts_found"] += c


def parse_pedalpcb_pdf(
filepath: str, source_name: str
) -> tuple[InventoryType, StatsDict]:
def parse_pedalpcb_pdf(filepath: str, source_name: str) -> tuple[Inventory, StatsDict]:
"""
Parses a PedalPCB Build Document (PDF).

Expand Down
6 changes: 3 additions & 3 deletions src/bom_lib/sourcing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from urllib.parse import quote_plus

import src.bom_lib.constants as C
from src.bom_lib.types import InventoryType, StatsDict
from src.bom_lib.types import Inventory, StatsDict
from src.bom_lib.utils import float_to_search_string, parse_value_to_float


Expand Down Expand Up @@ -58,7 +58,7 @@ def get_residual_report(stats: StatsDict) -> list[str]:
return suspicious


def get_injection_warnings(inventory: InventoryType) -> list[str]:
def get_injection_warnings(inventory: Inventory) -> list[str]:
"""
Generates user warnings based on automated hardware injections.

Expand Down Expand Up @@ -321,7 +321,7 @@ def get_buy_details(
return buy, note


def get_standard_hardware(inventory: InventoryType, pedal_count: int = 1) -> None:
def get_standard_hardware(inventory: Inventory, pedal_count: int = 1) -> None:
"""
Injects standard enclosure hardware into the inventory.

Expand Down
4 changes: 0 additions & 4 deletions src/bom_lib/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ def merge(self, other: "Inventory", multiplier: int = 1) -> None:
self[key]["sources"][src].extend(refs * multiplier)


# Update Type Alias to point to new Class for backward compatibility checks
InventoryType = Inventory


def create_empty_inventory() -> Inventory:
"""Factory function to return new Inventory instance."""
return Inventory()
7 changes: 4 additions & 3 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import pytest
from streamlit.testing.v1 import AppTest

from src.bom_lib import BOM_PRESETS, InventoryType, ProjectSlot
from src.bom_lib import BOM_PRESETS, ProjectSlot
from src.bom_lib.types import Inventory


# --- Helpers ---
Expand Down Expand Up @@ -79,7 +80,7 @@ def test_csv_processing_via_state_injection(app):
"""
# 1. Mock the inventory structure that the CSV parser WOULD have produced
mock_inventory = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)
mock_inventory["Resistors | 10k"]["qty"] = 5
Expand All @@ -90,7 +91,7 @@ def test_csv_processing_via_state_injection(app):

# Mock Stock (User already has 2x 10k resistors)
mock_stock = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)
mock_stock["Resistors | 10k"]["qty"] = 2
Expand Down
12 changes: 6 additions & 6 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from src.bom_lib import (
BOM_PRESETS,
InventoryType,
calculate_net_needs,
deduplicate_refs,
expand_refs,
Expand All @@ -34,6 +33,7 @@
parse_value_to_float,
parse_with_verification,
)
from src.bom_lib.types import Inventory

# --- Standard Unit Tests ---

Expand Down Expand Up @@ -306,7 +306,7 @@ def test_hardware_injection_and_smart_merge():
# Setup: Inventory has 2 existing 3.3k resistors (for the circuit)
# and 3 Pots (which implies we need 3 Knobs)
inventory = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)
inventory["Resistors | 3.3k"]["qty"] = 2
Expand Down Expand Up @@ -383,7 +383,7 @@ def test_fuzz_germanium_trigger():
"""
# Setup inventory with a Fuzz PCB
inventory = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)
inventory["PCB | Fuzz Face"]["qty"] = 1
Expand Down Expand Up @@ -444,7 +444,7 @@ def test_hardware_search_term_validity():
"""
# Fix: Must use defaultdict to prevent KeyError during injection
inventory = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)

Expand Down Expand Up @@ -567,15 +567,15 @@ def test_net_needs_calculation():
"""
# 1. Setup BOM
bom = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)
bom["Resistors | 10k"]["qty"] = 10 # Need 10
bom["Capacitors | 100n"]["qty"] = 5 # Need 5

# 2. Setup Stock
stock = cast(
InventoryType,
Inventory,
defaultdict(lambda: {"qty": 0, "refs": [], "sources": defaultdict(list)}),
)
stock["Resistors | 10k"]["qty"] = 4 # Have 4 (Deficit 6)
Expand Down