refactor(pry): rename 19 root modules to pry_<name> to remove naming collision with routers/

The duplicate file names (advanced, agency, auth, compliance, costing, etc.) in
both root and routers/ made imports ambiguous. Renamed root modules to
pry_<name>.py so:

  from quality import X     ->  from pry_quality import X
  from routers.quality import router  (unchanged)

Also:
- Renamed x402.py to pry_x402/ package directory
- Fixed 21+ bare imports across api.py, deps.py, routers/, tests/, llm_providers/

Tests: 593 passed, 1 skipped (test_ready_returns_200 fails pre-existing
because Ollama is unreachable from test env, unrelated to this refactor).

Audit item 8.
This commit is contained in:
Crypto Rug Munch 2026-07-06 10:25:44 +02:00
parent 090f284c37
commit 0ecc250349
48 changed files with 46 additions and 46 deletions

2
api.py
View file

@ -27,7 +27,7 @@ from errors import (
) )
from mcp_sse import mcp_post_message, mcp_sse_endpoint from mcp_sse import mcp_post_message, mcp_sse_endpoint
from observability import REQUEST_COUNT, REQUEST_LATENCY, setup_tracing from observability import REQUEST_COUNT, REQUEST_LATENCY, setup_tracing
from pipeline import get_pipeline from pry_pipeline import get_pipeline
from pry_mcp import make_fallback_server, register_all from pry_mcp import make_fallback_server, register_all
from routers.advanced import router as advanced_router from routers.advanced import router as advanced_router
from routers.agency import router as agency_router from routers.agency import router as agency_router

View file

@ -12,7 +12,7 @@ Usage:
# Copyright (c) 2026 Rug Munch Media LLC # Copyright (c) 2026 Rug Munch Media LLC
from __future__ import annotations from __future__ import annotations
from advanced import PryAdvanced from pry_advanced import PryAdvanced
from automator import PryAutomator from automator import PryAutomator
from cache import ResponseCache from cache import ResponseCache
from extractor import SchemaExtractor from extractor import SchemaExtractor

View file

@ -44,7 +44,7 @@ class ReferralConfig:
def __post_init__(self): def __post_init__(self):
if not self.referral_links: if not self.referral_links:
from referrals import PROVIDER_CATALOG from pry_referrals import PROVIDER_CATALOG
for _category, providers in PROVIDER_CATALOG.items(): for _category, providers in PROVIDER_CATALOG.items():
for p in providers: for p in providers:

View file

@ -146,7 +146,7 @@ class LLMRegistry:
u["last_used"] = datetime.now(UTC).isoformat() u["last_used"] = datetime.now(UTC).isoformat()
# NEW: track in-app LLM usage as referral revenue # NEW: track in-app LLM usage as referral revenue
try: try:
from referrals import ReferralTracker from pry_referrals import ReferralTracker
if not hasattr(self, "_referral_tracker"): if not hasattr(self, "_referral_tracker"):
self._referral_tracker = ReferralTracker() self._referral_tracker = ReferralTracker()

View file

@ -328,7 +328,7 @@ class ProxyManager:
if not provider: if not provider:
provider = PREMIUM_PROXY_PROVIDERS[0] provider = PREMIUM_PROXY_PROVIDERS[0]
try: try:
from referrals import ReferralTracker from pry_referrals import ReferralTracker
tracker = ReferralTracker() tracker = ReferralTracker()
tracker.record_click( tracker.record_click(
@ -435,7 +435,7 @@ class ProxyManager:
if not provider: if not provider:
return "" return ""
try: try:
from referrals import ReferralTracker from pry_referrals import ReferralTracker
tracker = ReferralTracker() tracker = ReferralTracker()
return tracker.record_click( return tracker.record_click(
@ -451,7 +451,7 @@ class ProxyManager:
def get_recent_clicks(self, days_back: int = 30) -> list[dict[str, Any]]: def get_recent_clicks(self, days_back: int = 30) -> list[dict[str, Any]]:
"""Get recent proxy referral clicks for revenue tracking.""" """Get recent proxy referral clicks for revenue tracking."""
try: try:
from referrals import ReferralTracker from pry_referrals import ReferralTracker
tracker = ReferralTracker() tracker = ReferralTracker()
cutoff = datetime.now(UTC).timestamp() - (days_back * 86400) cutoff = datetime.now(UTC).timestamp() - (days_back * 86400)

View file

@ -237,7 +237,7 @@ def make_fallback_server(
) )
if uri == "pry://x402/pricing": if uri == "pry://x402/pricing":
try: try:
from x402 import X402Handler from pry_x402 import X402Handler
return json.dumps(X402Handler().get_stats(), indent=2) return json.dumps(X402Handler().get_stats(), indent=2)
except (json.JSONDecodeError, ValueError) as e: except (json.JSONDecodeError, ValueError) as e:

View file

@ -19,7 +19,7 @@ from fastapi import APIRouter, Body
from client import get_client from client import get_client
from deps import advanced, scraper from deps import advanced, scraper
from errors import InvalidRequestError, ScrapeError from errors import InvalidRequestError, ScrapeError
from extraction import JsonCssExtractionStrategy, extract_with_chunking from pry_extraction import JsonCssExtractionStrategy, extract_with_chunking
from extractor import SchemaExtractor from extractor import SchemaExtractor
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View file

@ -14,7 +14,7 @@ from typing import Any
from fastapi import APIRouter, Body from fastapi import APIRouter, Body
from errors import InvalidRequestError from errors import InvalidRequestError
from pipeline import HOOK_POINTS, get_pipeline, run_pipeline from pry_pipeline import HOOK_POINTS, get_pipeline, run_pipeline
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View file

@ -23,7 +23,7 @@ router = APIRouter(tags=["x402"])
@router.get("/v1/x402/pricing", tags=["x402"], summary="Get x402 pricing for all paid operations") @router.get("/v1/x402/pricing", tags=["x402"], summary="Get x402 pricing for all paid operations")
async def x402_pricing() -> dict[str, Any]: async def x402_pricing() -> dict[str, Any]:
"""Get the price list for pay-per-scrape operations.""" """Get the price list for pay-per-scrape operations."""
from x402 import X402Handler from pry_x402 import X402Handler
return {"success": True, "data": X402Handler().get_stats()} return {"success": True, "data": X402Handler().get_stats()}
@ -37,7 +37,7 @@ async def x402_payment_request(
Returns payment details (wallet, amount, asset) for the client to pay. Returns payment details (wallet, amount, asset) for the client to pay.
""" """
from x402 import create_payment_request from pry_x402 import create_payment_request
req = create_payment_request(operation, metadata) req = create_payment_request(operation, metadata)
return {"success": True, "data": req} return {"success": True, "data": req}
@ -52,7 +52,7 @@ async def x402_verify_payment(
amount_usd: float = Body(0.0), amount_usd: float = Body(0.0),
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Verify a x402 payment has been settled on-chain via facilitator router.""" """Verify a x402 payment has been settled on-chain via facilitator router."""
from x402 import X402Handler from pry_x402 import X402Handler
result = await X402Handler().verify_payment( result = await X402Handler().verify_payment(
payment_id, tx_hash, network=network, asset=asset, amount_usd=amount_usd payment_id, tx_hash, network=network, asset=asset, amount_usd=amount_usd
@ -68,7 +68,7 @@ async def x402_require_payment(
metadata: dict[str, Any] | None = Body(None), metadata: dict[str, Any] | None = Body(None),
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Generate a 402 Payment Required response for a paid endpoint.""" """Generate a 402 Payment Required response for a paid endpoint."""
from x402 import require_payment_legacy from pry_x402 import require_payment_legacy
return require_payment_legacy(operation, metadata) return require_payment_legacy(operation, metadata)
@ -80,7 +80,7 @@ async def x402_batch_payment(payload: dict[str, Any] = Body(...)) -> dict[str, A
Returns a PaymentRequired body with the combined amount. After paying, Returns a PaymentRequired body with the combined amount. After paying,
submit the tx to POST /v1/x402/batch-verify. submit the tx to POST /v1/x402/batch-verify.
""" """
from x402 import create_batch_payment from pry_x402 import create_batch_payment
operations = payload.get("operations", []) operations = payload.get("operations", [])
if not isinstance(operations, list): if not isinstance(operations, list):
@ -94,7 +94,7 @@ async def x402_batch_payment(payload: dict[str, Any] = Body(...)) -> dict[str, A
@router.post("/v1/x402/batch-verify", tags=["x402"], summary="Verify a batch x402 payment") @router.post("/v1/x402/batch-verify", tags=["x402"], summary="Verify a batch x402 payment")
async def x402_batch_verify(payload: dict[str, Any] = Body(...)) -> dict[str, Any]: async def x402_batch_verify(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
"""Verify the on-chain payment for a batch and mark it paid.""" """Verify the on-chain payment for a batch and mark it paid."""
from x402 import verify_batch_payment from pry_x402 import verify_batch_payment
batch_id = payload.get("batch_id", "") batch_id = payload.get("batch_id", "")
tx_hash = payload.get("tx_hash", "") tx_hash = payload.get("tx_hash", "")
@ -128,7 +128,7 @@ async def x402_pay(
4. Pry verifies the transaction through the facilitator router 4. Pry verifies the transaction through the facilitator router
5. Returns access token (payment_id) to use in X-Payment-Hash header 5. Returns access token (payment_id) to use in X-Payment-Hash header
""" """
from x402 import X402Handler from pry_x402 import X402Handler
h = X402Handler() h = X402Handler()
payment_id = uuid.uuid4().hex[:12] payment_id = uuid.uuid4().hex[:12]

View file

@ -12,7 +12,7 @@ import logging
from pathlib import Path from pathlib import Path
from typing import Any, cast from typing import Any, cast
from extraction import JsonCssExtractionStrategy from pry_extraction import JsonCssExtractionStrategy
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for white-label agency dashboard.""" """Tests for white-label agency dashboard."""
from agency import ( from pry_agency import (
check_client_quota, check_client_quota,
create_agency, create_agency,
create_client, create_client,

View file

@ -55,7 +55,7 @@ class TestX402PublicSurface:
"""The x402 shim must expose the same public API as before.""" """The x402 shim must expose the same public API as before."""
def test_required_symbols_exist(self) -> None: def test_required_symbols_exist(self) -> None:
import x402 import pry_x402 as x402
required = { required = {
"X402Asset", "X402Asset",
@ -77,7 +77,7 @@ class TestX402PublicSurface:
assert not missing, f"Missing public x402 symbols: {missing}" assert not missing, f"Missing public x402 symbols: {missing}"
def test_enum_values_consistent(self) -> None: def test_enum_values_consistent(self) -> None:
import x402 import pry_x402 as x402
assert x402.X402Scheme.EXACT.value == "exact" assert x402.X402Scheme.EXACT.value == "exact"
assert x402.X402Network.ETHEREUM.value == "ethereum" assert x402.X402Network.ETHEREUM.value == "ethereum"

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for legal compliance engine.""" """Tests for legal compliance engine."""
from compliance import ( from pry_compliance import (
classify_tos, classify_tos,
detect_jurisdiction, detect_jurisdiction,
tag_sensitive_data, tag_sensitive_data,

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for cost analytics engine.""" """Tests for cost analytics engine."""
from costing import ( from pry_costing import (
DEFAULT_COST_TABLE, DEFAULT_COST_TABLE,
get_monthly_usage, get_monthly_usage,
record_usage, record_usage,

View file

@ -3,9 +3,9 @@
# #
# Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper # Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for data enrichment pipeline.""" """Tests for data.enrichment pipeline."""
from enrichment import ( from pry_enrichment import (
TECH_PATTERNS, TECH_PATTERNS,
detect_tech_stack, detect_tech_stack,
extract_company_info, extract_company_info,

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for adaptive freshness scheduling.""" """Tests for adaptive freshness scheduling."""
from freshness import ( from pry_freshness import (
calculate_adaptive_frequency, calculate_adaptive_frequency,
check_content_changed, check_content_changed,
compute_content_hash, compute_content_hash,

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for GDPR compliance portal.""" """Tests for GDPR compliance portal."""
from gdpr import ( from pry_gdpr import (
check_consent, check_consent,
get_retention_policy, get_retention_policy,
process_deletion, process_deletion,

View file

@ -7,7 +7,7 @@
import asyncio import asyncio
from auth import AuthManager, base64_decode, base64_encode from pry_auth import AuthManager, base64_decode, base64_encode
from db import _has_sqlalchemy, get_db from db import _has_sqlalchemy, get_db
from observability import track_llm_call, track_request, track_scrape from observability import track_llm_call, track_request, track_scrape
from tasks import JobQueue, JobStatus from tasks import JobQueue, JobStatus

View file

@ -3,7 +3,7 @@
# #
# Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper # Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for competitive intelligence engine.""" """Tests for competitive.intelligence engine."""
import time import time
from collections.abc import Iterator from collections.abc import Iterator
@ -11,7 +11,7 @@ from collections.abc import Iterator
import pytest import pytest
from db import Base, get_engine from db import Base, get_engine
from intelligence import ( from pry_intelligence import (
compute_field_statistics, compute_field_statistics,
detect_anomalies_numeric, detect_anomalies_numeric,
generate_alert, generate_alert,

View file

@ -27,7 +27,7 @@ import pytest
async def test_compliance_llm_fallback_merges_into_tos_result(): async def test_compliance_llm_fallback_merges_into_tos_result():
"""When tos_result confidence is low, the LLM result should be merged in """When tos_result confidence is low, the LLM result should be merged in
with the llm_enhanced flag set to True.""" with the llm_enhanced flag set to True."""
from compliance import run_compliance_check from pry_compliance import run_compliance_check
fake_llm = AsyncMock( fake_llm = AsyncMock(
return_value={ return_value={
@ -57,7 +57,7 @@ async def test_compliance_llm_fallback_merges_into_tos_result():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_compliance_llm_fallback_preserves_result_on_error(): async def test_compliance_llm_fallback_preserves_result_on_error():
"""If the LLM call raises, the regex result should be preserved (no crash).""" """If the LLM call raises, the regex result should be preserved (no crash)."""
from compliance import run_compliance_check from pry_compliance import run_compliance_check
fake_llm = AsyncMock(side_effect=RuntimeError("LLM down")) fake_llm = AsyncMock(side_effect=RuntimeError("LLM down"))
@ -127,7 +127,7 @@ async def test_seo_llm_enhancement_fills_empty_critical_fields():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_reconciliation_llm_enhance_function_exists(): async def test_reconciliation_llm_enhance_function_exists():
"""llm_enhance_reconciliation should be a callable that returns a dict.""" """llm_enhance_reconciliation should be a callable that returns a dict."""
from reconciliation import llm_enhance_reconciliation from pry_reconciliation import llm_enhance_reconciliation
fake_llm = AsyncMock(return_value={"is_same_entity": True}) fake_llm = AsyncMock(return_value={"is_same_entity": True})
@ -150,7 +150,7 @@ async def test_reconciliation_llm_enhance_function_exists():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_reconciliation_llm_enhance_handles_no_low_confidence(): async def test_reconciliation_llm_enhance_handles_no_low_confidence():
"""If all entities are high-confidence, the LLM should not be called.""" """If all entities are high-confidence, the LLM should not be called."""
from reconciliation import llm_enhance_reconciliation from pry_reconciliation import llm_enhance_reconciliation
fake_llm = AsyncMock(return_value={"is_same_entity": True}) fake_llm = AsyncMock(return_value={"is_same_entity": True})
@ -170,7 +170,7 @@ async def test_reconciliation_llm_enhance_handles_no_low_confidence():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_reconciliation_llm_enhance_handles_llm_error(): async def test_reconciliation_llm_enhance_handles_llm_error():
"""If the LLM call raises, return a degraded result without crashing.""" """If the LLM call raises, return a degraded result without crashing."""
from reconciliation import llm_enhance_reconciliation from pry_reconciliation import llm_enhance_reconciliation
fake_llm = AsyncMock(side_effect=ConnectionError("timeout")) fake_llm = AsyncMock(side_effect=ConnectionError("timeout"))

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for pipeline hook system.""" """Tests for pipeline hook system."""
from pipeline import HOOK_POINTS, Pipeline from pry_pipeline import HOOK_POINTS, Pipeline
def test_pipeline_init() -> None: def test_pipeline_init() -> None:

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for pipeline builder.""" """Tests for pipeline builder."""
from pipelines import ( from pry_pipelines import (
STEP_TYPES, STEP_TYPES,
list_pipelines, list_pipelines,
run_pipeline, run_pipeline,

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for data quality SLA dashboard.""" """Tests for data quality SLA dashboard."""
from quality import ( from pry_quality import (
compute_completeness, compute_completeness,
compute_freshness, compute_freshness,
compute_null_rate, compute_null_rate,

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for entity reconciliation.""" """Tests for entity reconciliation."""
from reconciliation import ( from pry_reconciliation import (
VERTICAL_SCHEMAS, VERTICAL_SCHEMAS,
_build_field_map, _build_field_map,
_normalize_record, _normalize_record,

View file

@ -9,8 +9,8 @@ from collections.abc import Iterator
import pytest import pytest
from referrals import PROVIDER_CATALOG, ReferralTracker from pry_referrals import PROVIDER_CATALOG, ReferralTracker
from x402 import X402_PRICING, X402Handler from pry_x402 import X402_PRICING, X402Handler
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for white-label report generation.""" """Tests for white-label report generation."""
from reports import generate_report, list_reports from pry_reports import generate_report, list_reports
def test_generate_competitive_report() -> None: def test_generate_competitive_report() -> None:

View file

@ -5,7 +5,7 @@
# Licensed under MIT. See LICENSE. # Licensed under MIT. See LICENSE.
"""Tests for human-in-the-loop review workflow.""" """Tests for human-in-the-loop review workflow."""
from review import ( from pry_review import (
REVIEW_STATUS, REVIEW_STATUS,
approve_review, approve_review,
get_review_queue, get_review_queue,

View file

@ -18,7 +18,7 @@ from pry_mcp import (
make_fallback_server, make_fallback_server,
register_all, register_all,
) )
from x402 import ( from pry_x402 import (
X402_PRICING, X402_PRICING,
FacilitatorRouter, FacilitatorRouter,
X402Asset, X402Asset,

View file

@ -25,7 +25,7 @@ import logging
from datetime import UTC, datetime from datetime import UTC, datetime
from typing import Any from typing import Any
from x402 import X402_PRICING, X402Handler from pry_x402 import X402_PRICING, X402Handler
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -91,7 +91,7 @@ class X402Middleware:
# Check pre-verified batch payment # Check pre-verified batch payment
if batch_id_header: if batch_id_header:
from x402 import is_batch_paid from pry_x402 import is_batch_paid
if is_batch_paid(batch_id_header): if is_batch_paid(batch_id_header):
await self.app(scope, receive, send) await self.app(scope, receive, send)