"""#2616 шаг 1: каждый прямой BrowserFetcher(...) в pipeline.py обязан прокидывать environment=. Ревью PR #2634 нашло: build_browser_fetcher() (providers/_base.py) — единственное место, где environment прокидывался, а avito-пути pipeline.py конструируют BrowserFetcher напрямую → guard NoProxyAvailableError был мёртв ровно для источника, ради которого писался (#2613). Юнит-тесты этого не ловили, потому что конструировали фетчер сами, а не путём pipeline. Source-level гард дешевле интеграционного прогона pipeline и падает на первом же новом construction-site без environment=. """ from __future__ import annotations import re from pathlib import Path _PIPELINE = ( Path(__file__).resolve().parents[2] / "packages" / "scraper-kit" / "src" / "scraper_kit" / "orchestration" / "pipeline.py" ) def test_every_direct_browserfetcher_construction_threads_environment() -> None: src = _PIPELINE.read_text(encoding="utf-8") # Все вызовы конструктора BrowserFetcher( ... ) — балансировку скобок не пишем, # берём консервативное окно в 15 строк после открытия вызова. sites = [m.start() for m in re.finditer(r"BrowserFetcher\(\n", src)] assert sites, "pipeline.py больше не конструирует BrowserFetcher напрямую? Обнови/удали тест." missing: list[str] = [] for pos in sites: window = src[pos : pos + 700] if "environment=" not in window: line_no = src[:pos].count("\n") + 1 missing.append(f"pipeline.py:{line_no}") assert not missing, ( f"Прямые BrowserFetcher(...) без environment= ({missing}): guard " "NoProxyAvailableError (#2616) для них мёртв — добавь " 'environment=getattr(config, "environment", "dev").' )