Files
janssen/Covance_UCO3001/download_test_results_v1.4.md
T
2026-05-29 14:07:57 +02:00

219 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# download_test_results_v1.4.py — dokumentace
**Verze:** 1.4 · **Datum:** 2026-05-29
**Umístění:** `U:\PythonProject\Janssen\Covance_UCO3001\download_test_results_v1.4.py`
> **Změny v1.4 oproti 1.3:** **retry na úrovni reportu.**
> Při paralelním běhu server občas vrátí timeout (zejm. `page.goto` 30 s,
> nebo `wait_for_function` 120 s na grid). Dřív byl takový report rovnou
> zapsán jako selhaný. Teď se každý report zkusí až **2× (MAX_ATTEMPTS=2)**,
> mezi pokusy 5 s pauza a `goto("about:blank")` jako reset. Většina
> přechodných timeoutů projde napodruhé.
> Launcher povýšen na `run_test_results_parallel_v1.2.py` (cílí na v1.4).
>
> **Změny v1.3 oproti 1.2:** robustní login (NEčekat na `networkidle`,
> čekat přímo na pole Email/Password) + okno se při pádu nezavře
> (try/except + input()).
> **Změny v1.2 oproti 1.1:** paralelní běh přes sharding (`--shard N --of M`).
> **Změny v1.1 oproti 1.0:** druhá studie 35472 (MDD) + report Microbiology.
---
## 1. Účel
Automatické stažení reportů **Test Results** z portálu Labcorp Sponsor Portal
(`xsp.labcorp.com`). Skript projde **2 studie × jejich centra × 2 typy reportu**,
u každého vyexportuje grid do CSV a uloží ho timestampovaný do `Source/`.
| Studie | Interní ID | Význam | Počet center |
|---|---|---|---|
| UC | `36940` | 77242113UCO3001 | 12 |
| MDD | `35472` | druhá studie | 5 |
Typy reportu: **Standard** (`/standard-test-results`) a **Microbiology** (`/microbiology`).
**Celkem: (12 + 5) × 2 = 34 reportů** (prázdná centra se přeskakují, viz 6.5).
---
## 2. Spuštění
### 2a) Paralelně (doporučeno — rychlejší)
```bat
U:\PythonProject\Janssen\.venv\Scripts\python.exe ^
U:\PythonProject\Janssen\Covance_UCO3001\run_test_results_parallel_v1.2.py
```
### 2b) Serialně (jeden proces)
```bat
U:\PythonProject\Janssen\.venv\Scripts\python.exe ^
U:\PythonProject\Janssen\Covance_UCO3001\download_test_results_v1.4.py
```
### 2c) Jeden konkrétní shard ručně
```bat
…\python.exe download_test_results_v1.4.py --shard 2 --of 4
```
- Prohlížeč běží **viditelně** (`headless=False`), maximalizovaný.
- Po dokončení (i po chybě) okno **čeká na Enter** — ať je vidět log.
---
## 3. Retry (v1.4)
### 3.1 Proč
Z reálného běhu 4 shardů (29. 5. 2026) ze 34 reportů selhaly 2:
- `930539/standard``page.goto` timeout 30 s (server vůbec neodpověděl)
- `930547/standard``wait_for_function` timeout 120 s (grid se nedotáhl)
Obojí jsou **přechodné serverové timeouty** (sharding ho zatěžuje). Stačí
počkat a zkusit znovu — propadne to.
### 3.2 Jak
Konstanty:
```python
MAX_ATTEMPTS = 2 # 1. pokus + 1 retry
RETRY_BACKOFF_S = 5 # pauza pred opakovanym pokusem
```
`download_report(page, report)` je wrapper, který volá
`download_report_once(...)` v cyklu 1..MAX_ATTEMPTS. Při výjimce zaloguje
`POKUS X/N SELHAL: …`, počká `RETRY_BACKOFF_S`, navštíví `about:blank`
(reset gridu), a zkusí znovu. Když selže poslední pokus, výjimka se propustí
ven a vnější smyčka v `main()` to zapíše do `failed`.
### 3.3 Co se nezopakuje
Login — ten je mimo retry. Pokud spadne login, shard skončí přes vnější
`try/except` v `__main__` s `FATAL: ...` a okno čeká na Enter.
---
## 4. Paralelní běh (sharding) — beze změny vůči v1.3
### 4.1 Rozdělení práce
```python
REPORTS = ALL_REPORTS[SHARD - 1::OF]
```
Shard 1 z 4 vezme indexy 0, 4, 8, … atd. Bez argumentů = serial.
### 4.2 Profil per shard
| Běh | Profil |
|---|---|
| serialní (`--of 1`) | `browser_profile/` |
| shard N (`--of M>1`) | `browser_profile_{N}/` |
Chrome zamyká adresář profilu → 2 instance nesdílí 1 profil.
### 4.3 Login (varianta B)
Každý shard se přihlásí sám (jen heslo, žádné MFA). Session se uloží do
`browser_profile_{N}/` → další běh login přeskočí. Launcher startuje
s rozestupem `STAGGER_S = 8 s`, aby se OKTA nezahltil.
### 4.4 Launcher `run_test_results_parallel_v1.2.py`
- `N_SHARDS = 4`, `STAGGER_S = 8 s`.
- Každý proces v novém okně (`CREATE_NEW_CONSOLE`) → logy se neprolínají.
- Prefix logu: `[S{shard}/{of}]`.
### 4.5 Reálné zrychlení
~23× (server throttluje exporty, ne přesně 4×).
---
## 5. Výstupní soubory
```
{YYYY-MM-DD_HHMMSS} sponsor-study-{STUDY}-test-results-{SITE_ID}-{TYP}.csv
```
Všechny shardy ukládají do `Source/`. Staré se **nikdy nemažou**.
---
## 6. Klíčové technické poznatky — ověřeno přes Chrome MCP
### 6.1 Čekání na data = `.ag-row`
-`wait_for_selector("div.ag-row")` (default visible) timeoutuje
(řádky jsou `position-absolute`).
-`wait_for_function("() => document.querySelectorAll('div.ag-row').length > 0")`.
- Stabilizace: počet se čte co 2 s, dokud se 2× neshodne.
- **Počet `.ag-row` je zastropený** (~153) virtuálním renderem. Export do
CSV ale vyexportuje VŠECHNY řádky.
### 6.2 „Fetching Data" / spinner — NEPLATÍ pro tuto stránku
Je jen na *samples* reportu. Signál = `.ag-row`.
### 6.3 Tři tečky (export) — DVA `<ag-export>`
`page.locator("ag-export button:visible", has_text="more_horiz").first.click()`
### 6.4 „Export to CSV" — DVĚ položky v DOM
`page.locator("mdl-menu-item:visible", has_text="Export to CSV").first.click()`
### 6.5 Prázdné centrum
- No-rows overlay `.ag-overlay-no-rows-wrapper` (NE `-no-rows-center`).
- 2 overlaye, 1 skrytý → kontrola `offsetParent !== null`.
- KROK 2 čeká na `.ag-row` **NEBO** prázdný overlay → nečeká 120 s zbytečně.
---
## 7. Login logika (v1.3+) — beze změny ve v1.4
```python
page.goto(LOGIN_URL)
try:
page.get_by_label("Email").wait_for(state="visible", timeout=12000)
except Exception:
return # session aktivni → login přeskočit
page.get_by_label("Email").fill(EMAIL)
page.get_by_role("button", name="Next").click()
page.get_by_label("Password").wait_for(state="visible", timeout=30000)
page.get_by_label("Password").fill(PASSWORD)
page.get_by_role("button", name="Verify").click()
page.wait_for_url(lambda url: "code=" not in url or "xsp." in url, timeout=60000)
```
**NE** `networkidle`. **NE** kontrola URL (po redirectu zůstává `xsp.covance.com`).
---
## 8. Chrome flagy
```
--disable-restore-session-state
--disable-session-crashed-bubble
```
---
## 9. Robustnost
- **Retry per report** (`MAX_ATTEMPTS = 2`) → přechodné timeouty propadnou.
- Každý report v `try/except` → chyba u jednoho nezastaví zbytek shardu.
- Celý běh shardu v `try/except` + `finally: input()` → okno se při pádu nezavře.
- Souhrn na konci: `hotovo X/Y (shard N/M)` + `SELHALA centra: …`.
- Launcher hlídá `returncode` každého shardu.
---
## 10. Možná budoucí rozšíření
- **Více pokusů:** zvednout `MAX_ATTEMPTS` (3+) — pro hodně přetížený server.
- **Více/méně procesů:** změnit `N_SHARDS` v launcheru (profily `_1.._N`).
- **Další studie / centra / typ reportu:** přidat do `STUDIES` / `REPORT_TYPES`.
- **Vyčistit profily:** smazat `browser_profile_*/` (vynutí nový login).
---
## 11. Příbuzné skripty
| Skript | Co stahuje |
|---|---|
| `download_samples_report_v1.1.py` | All Samples (sampletracking) |
| `download_kit_inventory_v2.1.py` | Kit inventory |
| `download_equeries_report_v1.1.py` | eQuery reporty (zdroj SITE_IDS pro 36940) |
| `download_test_results_v1.4.py` | **tento** — Test Results (Standard + Microbiology, 2 studie, sharding, retry) |
| `run_test_results_parallel_v1.2.py` | launcher 4 paralelních shardů test-results |