Ana içeriğe geç

Services API

selection_service.services.provider_registry.ProviderRegistry

Aktif provider örneklerini tutan merkezi kayıt defteri.

Kullanım

registry = ProviderRegistry.build( provider_names=[ProviderName.AFAD, ProviderName.PEER], use_cache=True, ) afad = registry.get("AFAD") all_providers = registry.all()

Source code in src/selection_service/services/provider_registry.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class ProviderRegistry:
    """Aktif provider örneklerini tutan merkezi kayıt defteri.

    Kullanım:
        registry = ProviderRegistry.build(
            provider_names=[ProviderName.AFAD, ProviderName.PEER],
            use_cache=True,
        )
        afad = registry.get("AFAD")
        all_providers = registry.all()
    """

    def __init__(self, providers: List[IDataFetcher]) -> None:
        # İsme göre O(1) arama için dict'e çevir
        self._providers: dict[str, IDataFetcher] = {
            p.get_name(): p for p in providers
        }

    # ── Factory ───────────────────────────────────────────────────

    @classmethod
    def build(
        cls,
        provider_names: List[ProviderName],
        use_cache: bool = True,
        **kwargs: Any,
    ) -> "ProviderRegistry":
        """ProviderName listesinden registry oluştur.

        Args:
            provider_names: Aktif edilecek provider'lar.
            use_cache:      True ise her provider CachedProviderProxy ile sarmalanır.
            **kwargs:       Provider'lara iletilen ek parametreler.
        """
        factory = ProviderFactory()
        providers = [
            factory.create_provider(name, use_cache=use_cache, **kwargs)
            for name in provider_names
        ]
        return cls(providers)

    # ── Erişim ────────────────────────────────────────────────────

    def get(self, name: str) -> Optional[IDataFetcher]:
        """İsme göre provider döndür; bulunamazsa None."""
        provider = self._providers.get(name)
        if provider is None:
            logger.warning("Provider '%s' registry'de bulunamadı.", name)
        return provider

    def all(self) -> List[IDataFetcher]:
        """Tüm kayıtlı provider örneklerini döndür."""
        return list(self._providers.values())

    def list_names(self) -> List[str]:
        """Kayıtlı provider isimlerini döndür."""
        return list(self._providers.keys())

build(provider_names, use_cache=True, **kwargs) classmethod

ProviderName listesinden registry oluştur.

Parameters:

Name Type Description Default
provider_names List[ProviderName]

Aktif edilecek provider'lar.

required
use_cache bool

True ise her provider CachedProviderProxy ile sarmalanır.

True
**kwargs Any

Provider'lara iletilen ek parametreler.

{}
Source code in src/selection_service/services/provider_registry.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@classmethod
def build(
    cls,
    provider_names: List[ProviderName],
    use_cache: bool = True,
    **kwargs: Any,
) -> "ProviderRegistry":
    """ProviderName listesinden registry oluştur.

    Args:
        provider_names: Aktif edilecek provider'lar.
        use_cache:      True ise her provider CachedProviderProxy ile sarmalanır.
        **kwargs:       Provider'lara iletilen ek parametreler.
    """
    factory = ProviderFactory()
    providers = [
        factory.create_provider(name, use_cache=use_cache, **kwargs)
        for name in provider_names
    ]
    return cls(providers)

get(name)

İsme göre provider döndür; bulunamazsa None.

Source code in src/selection_service/services/provider_registry.py
72
73
74
75
76
77
def get(self, name: str) -> Optional[IDataFetcher]:
    """İsme göre provider döndür; bulunamazsa None."""
    provider = self._providers.get(name)
    if provider is None:
        logger.warning("Provider '%s' registry'de bulunamadı.", name)
    return provider

all()

Tüm kayıtlı provider örneklerini döndür.

Source code in src/selection_service/services/provider_registry.py
79
80
81
def all(self) -> List[IDataFetcher]:
    """Tüm kayıtlı provider örneklerini döndür."""
    return list(self._providers.values())

list_names()

Kayıtlı provider isimlerini döndür.

Source code in src/selection_service/services/provider_registry.py
83
84
85
def list_names(self) -> List[str]:
    """Kayıtlı provider isimlerini döndür."""
    return list(self._providers.keys())

selection_service.services.earthquake_query_service.EarthquakeQueryService

Deprem kaydı sorgulama ve seçim servisi.

Bağımlılıklar dışarıdan enjekte edilir (DIP); bu sayede test ortamında sahte (fake) registry ve pipeline kullanılabilir.

Kullanım

registry = ProviderRegistry.build([ProviderName.AFAD, ProviderName.PEER]) strategies = [TBDYSelectionStrategy(config)] service = EarthquakeQueryService(registry, strategies)

result = service.run_sync(criteria, "TBDY_2018_Gaussian")

veya

result = await service.run_async(criteria, "TBDY_2018_Gaussian")

Source code in src/selection_service/services/earthquake_query_service.py
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
class EarthquakeQueryService:
    """Deprem kaydı sorgulama ve seçim servisi.

    Bağımlılıklar dışarıdan enjekte edilir (DIP); bu sayede
    test ortamında sahte (fake) registry ve pipeline kullanılabilir.

    Kullanım:
        registry = ProviderRegistry.build([ProviderName.AFAD, ProviderName.PEER])
        strategies = [TBDYSelectionStrategy(config)]
        service = EarthquakeQueryService(registry, strategies)

        result = service.run_sync(criteria, "TBDY_2018_Gaussian")
        # veya
        result = await service.run_async(criteria, "TBDY_2018_Gaussian")
    """

    def __init__(
        self,
        registry: ProviderRegistry,
        strategies: List[ISelectionStrategy],
        pipeline: EarthquakePipeline | None = None,
    ) -> None:
        self._registry = registry
        self._strategies: Dict[str, ISelectionStrategy] = {
            s.get_name(): s for s in strategies
        }
        # Pipeline dışarıdan verilebilir; verilmezse varsayılan oluşturulur.
        self._pipeline = pipeline or EarthquakePipeline()

    # ── Sorgulama ─────────────────────────────────────────────────

    async def run_async(
        self,
        criteria: SearchCriteria,
        strategy_name: str,
    ) -> Result[PipelineResult, PipelineError]:
        """Pipeline'ı asenkron çalıştır.

        Args:
            criteria:      Arama kriterleri (Pydantic ile doğrulanmış).
            strategy_name: Kullanılacak stratejinin adı (ör. 'TBDY_2018_Gaussian').

        Returns:
            Result.ok(PipelineResult) — başarı.
            Result.fail(PipelineError) — strateji bulunamadı veya pipeline hatası.
        """
        context = self._build_context(criteria, strategy_name)
        if isinstance(context, Result):
            return context
        return await self._pipeline.execute_async(context)

    def run_sync(
        self,
        criteria: SearchCriteria,
        strategy_name: str,
    ) -> Result[PipelineResult, PipelineError]:
        """Pipeline'ı senkron çalıştır.

        Args:
            criteria:      Arama kriterleri (Pydantic ile doğrulanmış).
            strategy_name: Kullanılacak stratejinin adı.

        Returns:
            Result.ok(PipelineResult) — başarı.
            Result.fail(PipelineError) — strateji bulunamadı veya pipeline hatası.
        """
        context = self._build_context(criteria, strategy_name)
        if isinstance(context, Result):
            return context
        return self._pipeline.execute_sync(context)

    # ── Re-selection ──────────────────────────────────────────────

    def re_selection(
        self,
        df: pd.DataFrame,
        strategy_name: str,
        new_criteria: SearchCriteria,
    ) -> Result[PipelineResult, PipelineError]:
        """Var olan veri üzerinde yeniden strateji uygula.

        Provider'lara tekrar sorgu atmadan, elinizdeki DataFrame üzerinde
        farklı bir strateji veya yeni kriterler denemenizi sağlar.

        Args:
            df:            Daha önce çekilmiş ve birleştirilmiş kayıt DataFrame'i.
            strategy_name: Uygulanacak stratejinin adı.
            new_criteria:  Yeni puanlama kriterleri ve ağırlıkları.

        Returns:
            Result.ok(PipelineResult) — başarı; execution_time=0.0 (fetch yok).
            Result.fail(StrategyError) — strateji bulunamadı veya uygulama hatası.
        """
        strategy = self._get_strategy(strategy_name)
        if strategy is None:
            return Result.fail(
                StrategyError(
                    f"Strategy '{strategy_name}' not found. "
                    f"Available: {list(self._strategies.keys())}"
                )
            )

        try:
            selected, scored = strategy.select_and_score(df, new_criteria)

            # Rapor üretmek için minimal bir context oluştur.
            # Provider listesi boş; sadece strateji + veri kullanılır.
            dummy_ctx = PipelineContext(
                providers=[],
                strategy=strategy,
                search_criteria=new_criteria,
            )
            dummy_ctx.selected_df = selected
            dummy_ctx.scored_df = scored

            report = self._pipeline.reporter.generate_report(dummy_ctx)

            return Result.ok(
                PipelineResult(
                    selected_df=selected,
                    scored_df=scored,
                    report=report,
                    execution_time=0.0,
                )
            )
        except Exception as e:
            return Result.fail(StrategyError(f"Re-selection failed: {e}"))

    # ── Yardımcı erişimciler ──────────────────────────────────────

    def list_strategies(self) -> List[str]:
        """Kayıtlı strateji isimlerini döndür."""
        return list(self._strategies.keys())

    def list_providers(self) -> List[str]:
        """Aktif provider isimlerini döndür."""
        return self._registry.list_names()

    # ── Private ───────────────────────────────────────────────────

    def _build_context(
        self,
        criteria: SearchCriteria,
        strategy_name: str,
    ) -> PipelineContext | Result:
        """PipelineContext oluştur; strateji yoksa Result.fail döndür."""
        strategy = self._get_strategy(strategy_name)
        if strategy is None:
            return Result.fail(
                PipelineError(
                    f"Strategy '{strategy_name}' not found. "
                    f"Available: {list(self._strategies.keys())}"
                )
            )
        return PipelineContext(
            providers=self._registry.all(),
            strategy=strategy,
            search_criteria=criteria,
        )

    def _get_strategy(self, name: str) -> ISelectionStrategy | None:
        strategy = self._strategies.get(name)
        if strategy is None:
            logger.warning(
                "Strategy '%s' bulunamadı. Mevcut: %s",
                name,
                list(self._strategies.keys()),
            )
        return strategy

run_async(criteria, strategy_name) async

Pipeline'ı asenkron çalıştır.

Parameters:

Name Type Description Default
criteria SearchCriteria

Arama kriterleri (Pydantic ile doğrulanmış).

required
strategy_name str

Kullanılacak stratejinin adı (ör. 'TBDY_2018_Gaussian').

required

Returns:

Type Description
Result[PipelineResult, PipelineError]

Result.ok(PipelineResult) — başarı.

Result[PipelineResult, PipelineError]

Result.fail(PipelineError) — strateji bulunamadı veya pipeline hatası.

Source code in src/selection_service/services/earthquake_query_service.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
async def run_async(
    self,
    criteria: SearchCriteria,
    strategy_name: str,
) -> Result[PipelineResult, PipelineError]:
    """Pipeline'ı asenkron çalıştır.

    Args:
        criteria:      Arama kriterleri (Pydantic ile doğrulanmış).
        strategy_name: Kullanılacak stratejinin adı (ör. 'TBDY_2018_Gaussian').

    Returns:
        Result.ok(PipelineResult) — başarı.
        Result.fail(PipelineError) — strateji bulunamadı veya pipeline hatası.
    """
    context = self._build_context(criteria, strategy_name)
    if isinstance(context, Result):
        return context
    return await self._pipeline.execute_async(context)

run_sync(criteria, strategy_name)

Pipeline'ı senkron çalıştır.

Parameters:

Name Type Description Default
criteria SearchCriteria

Arama kriterleri (Pydantic ile doğrulanmış).

required
strategy_name str

Kullanılacak stratejinin adı.

required

Returns:

Type Description
Result[PipelineResult, PipelineError]

Result.ok(PipelineResult) — başarı.

Result[PipelineResult, PipelineError]

Result.fail(PipelineError) — strateji bulunamadı veya pipeline hatası.

Source code in src/selection_service/services/earthquake_query_service.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def run_sync(
    self,
    criteria: SearchCriteria,
    strategy_name: str,
) -> Result[PipelineResult, PipelineError]:
    """Pipeline'ı senkron çalıştır.

    Args:
        criteria:      Arama kriterleri (Pydantic ile doğrulanmış).
        strategy_name: Kullanılacak stratejinin adı.

    Returns:
        Result.ok(PipelineResult) — başarı.
        Result.fail(PipelineError) — strateji bulunamadı veya pipeline hatası.
    """
    context = self._build_context(criteria, strategy_name)
    if isinstance(context, Result):
        return context
    return self._pipeline.execute_sync(context)

re_selection(df, strategy_name, new_criteria)

Var olan veri üzerinde yeniden strateji uygula.

Provider'lara tekrar sorgu atmadan, elinizdeki DataFrame üzerinde farklı bir strateji veya yeni kriterler denemenizi sağlar.

Parameters:

Name Type Description Default
df DataFrame

Daha önce çekilmiş ve birleştirilmiş kayıt DataFrame'i.

required
strategy_name str

Uygulanacak stratejinin adı.

required
new_criteria SearchCriteria

Yeni puanlama kriterleri ve ağırlıkları.

required

Returns:

Type Description
Result[PipelineResult, PipelineError]

Result.ok(PipelineResult) — başarı; execution_time=0.0 (fetch yok).

Result[PipelineResult, PipelineError]

Result.fail(StrategyError) — strateji bulunamadı veya uygulama hatası.

Source code in src/selection_service/services/earthquake_query_service.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
def re_selection(
    self,
    df: pd.DataFrame,
    strategy_name: str,
    new_criteria: SearchCriteria,
) -> Result[PipelineResult, PipelineError]:
    """Var olan veri üzerinde yeniden strateji uygula.

    Provider'lara tekrar sorgu atmadan, elinizdeki DataFrame üzerinde
    farklı bir strateji veya yeni kriterler denemenizi sağlar.

    Args:
        df:            Daha önce çekilmiş ve birleştirilmiş kayıt DataFrame'i.
        strategy_name: Uygulanacak stratejinin adı.
        new_criteria:  Yeni puanlama kriterleri ve ağırlıkları.

    Returns:
        Result.ok(PipelineResult) — başarı; execution_time=0.0 (fetch yok).
        Result.fail(StrategyError) — strateji bulunamadı veya uygulama hatası.
    """
    strategy = self._get_strategy(strategy_name)
    if strategy is None:
        return Result.fail(
            StrategyError(
                f"Strategy '{strategy_name}' not found. "
                f"Available: {list(self._strategies.keys())}"
            )
        )

    try:
        selected, scored = strategy.select_and_score(df, new_criteria)

        # Rapor üretmek için minimal bir context oluştur.
        # Provider listesi boş; sadece strateji + veri kullanılır.
        dummy_ctx = PipelineContext(
            providers=[],
            strategy=strategy,
            search_criteria=new_criteria,
        )
        dummy_ctx.selected_df = selected
        dummy_ctx.scored_df = scored

        report = self._pipeline.reporter.generate_report(dummy_ctx)

        return Result.ok(
            PipelineResult(
                selected_df=selected,
                scored_df=scored,
                report=report,
                execution_time=0.0,
            )
        )
    except Exception as e:
        return Result.fail(StrategyError(f"Re-selection failed: {e}"))

list_strategies()

Kayıtlı strateji isimlerini döndür.

Source code in src/selection_service/services/earthquake_query_service.py
162
163
164
def list_strategies(self) -> List[str]:
    """Kayıtlı strateji isimlerini döndür."""
    return list(self._strategies.keys())

list_providers()

Aktif provider isimlerini döndür.

Source code in src/selection_service/services/earthquake_query_service.py
166
167
168
def list_providers(self) -> List[str]:
    """Aktif provider isimlerini döndür."""
    return self._registry.list_names()

selection_service.services.waveform_download_service.WaveformDownloadService

Dalga formu indirme servisi.

Bağımlılıklar dışarıdan enjekte edilir; test ortamında sahte (fake) registry kullanılabilir.

Kullanım

registry = ProviderRegistry.build([ProviderName.AFAD]) downloader = WaveformDownloadService(registry)

result = downloader.download_batch(result_df, export_type="mseed") result = downloader.download_single("file.mseed", "12345", "AFAD.TK.KND")

Source code in src/selection_service/services/waveform_download_service.py
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
class WaveformDownloadService:
    """Dalga formu indirme servisi.

    Bağımlılıklar dışarıdan enjekte edilir; test ortamında
    sahte (fake) registry kullanılabilir.

    Kullanım:
        registry = ProviderRegistry.build([ProviderName.AFAD])
        downloader = WaveformDownloadService(registry)

        result = downloader.download_batch(result_df, export_type="mseed")
        result = downloader.download_single("file.mseed", "12345", "AFAD.TK.KND")
    """

    def __init__(self, registry: ProviderRegistry) -> None:
        self._registry = registry

    # ── Toplu indirme ─────────────────────────────────────────────

    def download_batch(
        self,
        result_df: pd.DataFrame,
        **kwargs: Any,
    ) -> Result[bool, ProviderError]:
        """Sonuç DataFrame'indeki tüm kayıtları toplu indir.

        DataFrame'i PROVIDER sütununa göre gruplar; her grup için
        ilgili provider'ın download_waveforms_batch metodunu çağırır.
        Download desteklemeyen provider'lar (PEER vb.) atlanır.

        Args:
            result_df: run_sync / run_async çıktısındaki selected_df.
            **kwargs:  Provider'a iletilen parametreler
                       (export_type, file_status, batch_size, …).

        Returns:
            Result.ok(True)  — en az bir batch başarıyla tamamlandı.
            Result.fail(e)   — tüm provider'lar başarısız oldu veya
                               beklenmedik bir hata oluştu.
        """
        if "PROVIDER" not in result_df.columns:
            return Result.fail(
                ProviderError(
                    "DownloadService",
                    ValueError("result_df 'PROVIDER' sütunu içermiyor."),
                    "Download failed",
                )
            )

        try:
            attempted = 0
            successful = 0
            failures: list[str] = []

            for provider_name, group in result_df.groupby("PROVIDER"):
                provider = self._provider(str(provider_name))

                if provider is None:
                    logger.warning(
                        "Provider '%s' registry'de yok, atlanıyor.", provider_name
                    )
                    continue

                if not supports_download(provider):
                    logger.info(
                        "%s download desteklemiyor, atlanıyor.", provider_name
                    )
                    continue

                filenames = group["FILE_NAME_H1"].tolist()
                event_ids = (
                    group["EVENT"].tolist() if "EVENT" in group.columns else None
                )

                logger.info(
                    "%s için %d dosya toplu indirme başlıyor.",
                    provider_name, len(filenames),
                )
                attempted += 1
                provider_result = provider.download_waveforms_batch(
                    filenames=filenames,
                    event_ids=event_ids,
                    **kwargs,
                )
                if self._provider_result_success(provider_result):
                    successful += 1
                else:
                    failures.append(f"{provider_name}: {provider_result}")

            if attempted > 0 and successful == 0:
                return Result.fail(
                    ProviderError(
                        "DownloadService",
                        RuntimeError("; ".join(failures) or "No provider download succeeded"),
                        "Bulk download failed",
                    )
                )
            return Result.ok(True)

        except Exception as e:
            return Result.fail(ProviderError("DownloadService", e, "Bulk download failed"))

    # ── Tekil indirme ─────────────────────────────────────────────

    def download_single(
        self,
        filename: str,
        event_id: str,
        station_code: str,
        **kwargs: Any,
    ) -> Result[bool, ProviderError]:
        """Tek bir dalga formu dosyasını indir.

        station_code'un ilk segmentinden (nokta öncesi) provider adı çıkarılır.
        Örnek: "AFAD.TK.KND" → provider adı "AFAD"

        Args:
            filename:     İndirilecek dosyanın adı.
            event_id:     İlgili deprem olayının ID'si.
            station_code: Noktalı istasyon kodu (ör. "AFAD.TK.KND").
            **kwargs:     Provider'a iletilen ek parametreler.

        Returns:
            Result.ok(True)  — dosya başarıyla indirildi.
            Result.fail(e)   — provider bulunamadı, download desteklenmiyor
                               veya ağ / dosya sistemi hatası.
        """
        provider_name = station_code.split(".")[0]
        provider = self._provider(provider_name)

        if provider is None:
            return Result.fail(
                ProviderError(
                    "DownloadService",
                    ValueError(f"Provider '{provider_name}' bulunamadı (station: {station_code})."),
                    "Download failed",
                )
            )

        if not supports_download(provider):
            return Result.fail(
                ProviderError(
                    provider_name,
                    NotImplementedError(
                        f"{provider_name} dalga formu indirmeyi desteklemiyor."
                    ),
                    "Download not supported",
                )
            )

        try:
            provider_result = provider.download_single_waveforms(
                filename=filename,
                event_id=event_id,
                station_code=station_code,
                **kwargs,
            )
            if not self._provider_result_success(provider_result):
                return Result.fail(
                    ProviderError(provider_name, RuntimeError(str(provider_result)), "Single waveform download failed")
                )
            return Result.ok(True)

        except Exception as e:
            return Result.fail(
                ProviderError(provider_name, e, "Single waveform download failed")
            )

    def _provider(self, name: str) -> Any:
        """Satirdaki PROVIDER adindan kayit defterindeki provider'i bulur.

        FDSN satirlari dugumle etiketlenir (``FDSN_USGS``); kayit defterinde tek
        ``FDSN`` provider'i vardir.
        """
        if name.upper().startswith("FDSN_"):
            name = ProviderName.FDSN.value
        return self._registry.get(name)

    def _provider_result_success(self, provider_result: Any) -> bool:
        if isinstance(provider_result, Result):
            if not provider_result.success:
                return False
            provider_result = provider_result.value

        if isinstance(provider_result, dict):
            downloaded = int(provider_result.get("downloaded", 0) or 0)
            total = int(provider_result.get("total", 0) or 0)
            failed_batches = [
                batch
                for batch in provider_result.get("batches", [])
                if batch.get("success") is False and not batch.get("retry_recovered")
            ]
            return downloaded > 0 and (total == 0 or downloaded >= total or not failed_batches)

        return provider_result is not False

download_batch(result_df, **kwargs)

Sonuç DataFrame'indeki tüm kayıtları toplu indir.

DataFrame'i PROVIDER sütununa göre gruplar; her grup için ilgili provider'ın download_waveforms_batch metodunu çağırır. Download desteklemeyen provider'lar (PEER vb.) atlanır.

Parameters:

Name Type Description Default
result_df DataFrame

run_sync / run_async çıktısındaki selected_df.

required
**kwargs Any

Provider'a iletilen parametreler (export_type, file_status, batch_size, …).

{}

Returns:

Type Description
Result[bool, ProviderError]

Result.ok(True) — en az bir batch başarıyla tamamlandı.

Result[bool, ProviderError]

Result.fail(e) — tüm provider'lar başarısız oldu veya beklenmedik bir hata oluştu.

Source code in src/selection_service/services/waveform_download_service.py
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def download_batch(
    self,
    result_df: pd.DataFrame,
    **kwargs: Any,
) -> Result[bool, ProviderError]:
    """Sonuç DataFrame'indeki tüm kayıtları toplu indir.

    DataFrame'i PROVIDER sütununa göre gruplar; her grup için
    ilgili provider'ın download_waveforms_batch metodunu çağırır.
    Download desteklemeyen provider'lar (PEER vb.) atlanır.

    Args:
        result_df: run_sync / run_async çıktısındaki selected_df.
        **kwargs:  Provider'a iletilen parametreler
                   (export_type, file_status, batch_size, …).

    Returns:
        Result.ok(True)  — en az bir batch başarıyla tamamlandı.
        Result.fail(e)   — tüm provider'lar başarısız oldu veya
                           beklenmedik bir hata oluştu.
    """
    if "PROVIDER" not in result_df.columns:
        return Result.fail(
            ProviderError(
                "DownloadService",
                ValueError("result_df 'PROVIDER' sütunu içermiyor."),
                "Download failed",
            )
        )

    try:
        attempted = 0
        successful = 0
        failures: list[str] = []

        for provider_name, group in result_df.groupby("PROVIDER"):
            provider = self._provider(str(provider_name))

            if provider is None:
                logger.warning(
                    "Provider '%s' registry'de yok, atlanıyor.", provider_name
                )
                continue

            if not supports_download(provider):
                logger.info(
                    "%s download desteklemiyor, atlanıyor.", provider_name
                )
                continue

            filenames = group["FILE_NAME_H1"].tolist()
            event_ids = (
                group["EVENT"].tolist() if "EVENT" in group.columns else None
            )

            logger.info(
                "%s için %d dosya toplu indirme başlıyor.",
                provider_name, len(filenames),
            )
            attempted += 1
            provider_result = provider.download_waveforms_batch(
                filenames=filenames,
                event_ids=event_ids,
                **kwargs,
            )
            if self._provider_result_success(provider_result):
                successful += 1
            else:
                failures.append(f"{provider_name}: {provider_result}")

        if attempted > 0 and successful == 0:
            return Result.fail(
                ProviderError(
                    "DownloadService",
                    RuntimeError("; ".join(failures) or "No provider download succeeded"),
                    "Bulk download failed",
                )
            )
        return Result.ok(True)

    except Exception as e:
        return Result.fail(ProviderError("DownloadService", e, "Bulk download failed"))

download_single(filename, event_id, station_code, **kwargs)

Tek bir dalga formu dosyasını indir.

station_code'un ilk segmentinden (nokta öncesi) provider adı çıkarılır. Örnek: "AFAD.TK.KND" → provider adı "AFAD"

Parameters:

Name Type Description Default
filename str

İndirilecek dosyanın adı.

required
event_id str

İlgili deprem olayının ID'si.

required
station_code str

Noktalı istasyon kodu (ör. "AFAD.TK.KND").

required
**kwargs Any

Provider'a iletilen ek parametreler.

{}

Returns:

Type Description
Result[bool, ProviderError]

Result.ok(True) — dosya başarıyla indirildi.

Result[bool, ProviderError]

Result.fail(e) — provider bulunamadı, download desteklenmiyor veya ağ / dosya sistemi hatası.

Source code in src/selection_service/services/waveform_download_service.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
def download_single(
    self,
    filename: str,
    event_id: str,
    station_code: str,
    **kwargs: Any,
) -> Result[bool, ProviderError]:
    """Tek bir dalga formu dosyasını indir.

    station_code'un ilk segmentinden (nokta öncesi) provider adı çıkarılır.
    Örnek: "AFAD.TK.KND" → provider adı "AFAD"

    Args:
        filename:     İndirilecek dosyanın adı.
        event_id:     İlgili deprem olayının ID'si.
        station_code: Noktalı istasyon kodu (ör. "AFAD.TK.KND").
        **kwargs:     Provider'a iletilen ek parametreler.

    Returns:
        Result.ok(True)  — dosya başarıyla indirildi.
        Result.fail(e)   — provider bulunamadı, download desteklenmiyor
                           veya ağ / dosya sistemi hatası.
    """
    provider_name = station_code.split(".")[0]
    provider = self._provider(provider_name)

    if provider is None:
        return Result.fail(
            ProviderError(
                "DownloadService",
                ValueError(f"Provider '{provider_name}' bulunamadı (station: {station_code})."),
                "Download failed",
            )
        )

    if not supports_download(provider):
        return Result.fail(
            ProviderError(
                provider_name,
                NotImplementedError(
                    f"{provider_name} dalga formu indirmeyi desteklemiyor."
                ),
                "Download not supported",
            )
        )

    try:
        provider_result = provider.download_single_waveforms(
            filename=filename,
            event_id=event_id,
            station_code=station_code,
            **kwargs,
        )
        if not self._provider_result_success(provider_result):
            return Result.fail(
                ProviderError(provider_name, RuntimeError(str(provider_result)), "Single waveform download failed")
            )
        return Result.ok(True)

    except Exception as e:
        return Result.fail(
            ProviderError(provider_name, e, "Single waveform download failed")
        )