treefmt v2.5.0ERRO formatter | ruff-check: failed to apply with options '[check --fix]': exit status 1 DTZ011 `datetime.date.today()` used --> eval/seed-recall/run.py:107:20 | 106 | db = PGStore(settings.pg_conninfo) 107 | current_year = datetime.date.today().year | ^^^^^^^^^^^^^^^^^^^^^ 108 | seed_scores: list[tuple[str, float]] = [] 109 | for seed in seeds: | help: Use `datetime.datetime.now(tz=...).date()` instead PLW1510 `subprocess.run` without explicit `check` argument --> quarry/assets/download.py:237:11 | 236 | # Dry-run to count pending operations 237 | dry = subprocess.run( | ^^^^^^^^^^^^^^ 238 | base_cmd + ["--dryrun"], 239 | capture_output=True, | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> quarry/assets/load.py:403:16 | 401 | def _optimize(table: str) -> tuple[str, int, str]: 402 | query = f"OPTIMIZE TABLE {table} FINAL" 403 | proc = subprocess.run( | ^^^^^^^^^^^^^^ 404 | _ch_client_cmd() + ["--query", query], 405 | capture_output=True, | help: Add explicit `check=False` ISC004 Unparenthesized implicit string concatenation in collection --> quarry/assets/load.py:510:9 | 508 | "papers_export", 509 | "papers", 510 | / "pmid, doi, pmc_id, title, abstract, pub_year, pub_date, " 511 | | "journal_title, journal_issn, journal_abbr, volume, issue, pages, " 512 | | "language, pub_type, country, medline_status, created_date, revised_date, " 513 | | "indexed_date, is_deleted, deleted_date, rcr, nih_percentile, apt, " 514 | | "is_clinical, human, animal, molecular_cellular, field_citation_rate", | |_____________________________________________________________________________^ 515 | ), 516 | ( | help: Did you forget a comma? help: Wrap implicitly concatenated strings in parentheses ISC004 Unparenthesized implicit string concatenation in collection --> quarry/assets/load.py:519:9 | 517 | "oa_work_authors", 518 | "work_authors", 519 | / "work_id, author_position, display_name, orcid, " 520 | | "institution_name, institution_ror, raw_affiliation", | |____________________________________________________________^ 521 | ), 522 | ( | help: Did you forget a comma? help: Wrap implicitly concatenated strings in parentheses ISC004 Unparenthesized implicit string concatenation in collection --> quarry/assets/load.py:530:9 | 528 | "pm_authors", 529 | "authors", 530 | / "pmid, author_position, last_name, fore_name, initials, " 531 | | "orcid, affiliation, is_collective", | |___________________________________________^ 532 | ), 533 | ( | help: Did you forget a comma? help: Wrap implicitly concatenated strings in parentheses ISC004 Unparenthesized implicit string concatenation in collection --> quarry/assets/load.py:536:9 | 534 | "pm_mesh_headings", 535 | "mesh_headings", 536 | / "pmid, descriptor_ui, descriptor_name, qualifier_ui, " 537 | | "qualifier_name, is_major_topic", | |________________________________________^ 538 | ), 539 | ("pm_grants", "grants", "pmid, grant_id, acronym, agency, country"), | help: Did you forget a comma? help: Wrap implicitly concatenated strings in parentheses ISC004 Unparenthesized implicit string concatenation in collection --> quarry/assets/load.py:557:9 | 555 | "work_mesh_export", 556 | "work_mesh", 557 | / "work_id, descriptor_ui, descriptor_name, qualifier_ui, " 558 | | "qualifier_name, is_major_topic", | |________________________________________^ 559 | ), 560 | ("cited_by_clin_export", "cited_by_clin", "pmid, citing_pmid"), | help: Did you forget a comma? help: Wrap implicitly concatenated strings in parentheses PLW1510 `subprocess.run` without explicit `check` argument --> quarry/assets/load.py:574:16 | 572 | cmd = _ch_client_cmd() + ["--query", query + " FORMAT Parquet"] 573 | with open(out_path, "wb") as f: 574 | return subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True) | ^^^^^^^^^^^^^^ help: Add explicit `check=False` BLE001 Do not catch blind exception: `Exception` --> quarry/assets/load.py:843:20 | 841 | done += 1 842 | context.log.info(f"[PG] {name} done [{done}/{total}]") 843 | except Exception as exc: | ^^^^^^^^^ 844 | context.log.error(f"[PG] {name} failed: {exc}") 845 | failed.append(name) | B008 Do not perform function call `typer.Argument` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable --> quarry/cli.py:56:27 | 54 | @app.command() 55 | def info( 56 | work_ids: list[str] = typer.Argument( | ___________________________^ 57 | | ..., help="One or more work IDs: W, DOI, PMID" 58 | | ), | |_____^ 59 | full: bool = typer.Option(False, "--full", help="Show full abstract"), 60 | show_mesh: bool = typer.Option(False, "--mesh", help="Show MeSH descriptors"), | PIE810 Call `startswith` once with a `tuple` --> quarry/cli.py:163:8 | 162 | # DOI 163 | if identifier.startswith("10.") or identifier.startswith("https://doi.org/"): | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 164 | doi = "https://doi.org/" + identifier.removeprefix("https://doi.org/").lower() 165 | return db.get_work_by_doi(doi) | help: Merge into a single `startswith` call B008 Do not perform function call `typer.Argument` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable --> quarry/cli.py:690:24 | 688 | @app.command() 689 | def bridge( 690 | seeds: list[str] = typer.Argument( | ________________________^ 691 | | ..., 692 | | help="Two or more seed papers: work_id_int, W, DOI, or https://doi.org/...", 693 | | ), | |_____^ 694 | types: list[str] = typer.Option( 695 | None, | B008 Do not perform function call `typer.Option` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable --> quarry/cli.py:694:24 | 692 | help="Two or more seed papers: work_id_int, W, DOI, or https://doi.org/...", 693 | ), 694 | types: list[str] = typer.Option( | ________________________^ 695 | | None, 696 | | "--type", 697 | | "-t", 698 | | help="Bridge types to compute (default: all). " 699 | | "Options: common_refs, common_citers, coupling, cocitation, path, ppr", 700 | | ), | |_____^ 701 | limit: int = typer.Option(100, "--limit", "-n", help="Max results per type"), 702 | max_neighbor_degree: int = typer.Option( | PIE810 Call `startswith` once with a `tuple` --> quarry/core/expand.py:211:8 | 210 | # DOI — normalize to OA format 211 | if seed.startswith("10.") or seed.startswith("https://doi.org/"): | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 212 | doi = "https://doi.org/" + seed.removeprefix("https://doi.org/").lower() 213 | with psycopg.connect(pg_conninfo) as conn, conn.cursor() as cur: | help: Merge into a single `startswith` call BLE001 Do not catch blind exception: `Exception` --> quarry/core/expand.py:259:12 | 257 | result[row[0]] = entry 258 | return result 259 | except Exception: | ^^^^^^^^^ 260 | return {} | PLW1510 `subprocess.run` without explicit `check` argument --> quarry/etl/embeddings.py:60:12 | 58 | def _ch_exec(query: str) -> str: 59 | """Execute CH query, return stdout. Raises on error.""" 60 | proc = subprocess.run( | ^^^^^^^^^^^^^^ 61 | _ch_cmd() + ["--query", query], 62 | capture_output=True, | help: Add explicit `check=False` BLE001 Do not catch blind exception: `Exception` --> quarry/etl/embeddings.py:335:16 | 333 | try: 334 | _ch_exec(f"DROP TABLE IF EXISTS {table}") 335 | except Exception as exc: | ^^^^^^^^^ 336 | logger.warning("Failed to drop %s: %s", table, exc) | BLE001 Do not catch blind exception: `Exception` --> quarry/etl/embeddings.py:352:12 | 350 | logger.info("Building work_id BTree index for hash lookups...") 351 | lance.create_scalar_index("work_id") 352 | except Exception: | ^^^^^^^^^ 353 | lance.create_table() | SIM113 Use `enumerate()` for index variable `batch_num` in `for` loop --> quarry/etl/embeddings.py:407:13 | 406 | total_encoded += len(to_encode) 407 | batch_num += 1 | ^^^^^^^^^^^^^^ 408 | throughput = len(texts) / elapsed if elapsed > 0 else 0 | DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z --> quarry/etl/fetch.py:68:29 | 66 | if modify: 67 | try: 68 | remote_ts = datetime.strptime(modify[:14], "%Y%m%d%H%M%S") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 69 | local_ts = datetime.fromtimestamp(local_path.stat().st_mtime) 70 | if remote_ts > local_ts: | help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument --> quarry/etl/fetch.py:69:28 | 67 | try: 68 | remote_ts = datetime.strptime(modify[:14], "%Y%m%d%H%M%S") 69 | local_ts = datetime.fromtimestamp(local_path.stat().st_mtime) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 70 | if remote_ts > local_ts: 71 | to_download.append(name) | help: Pass a `datetime.timezone` object to the `tz` parameter S110 `try`-`except`-`pass` detected, consider logging the exception --> quarry/etl/fetch.py:121:29 | 119 | … try: 120 | … conn.close() 121 | / … except Exception: 122 | | … pass | |______________________________^ 123 | … conn = ftplib.FTP(host, timeout=120) 124 | … conn.login() | BLE001 Do not catch blind exception: `Exception` --> quarry/etl/fetch.py:121:36 | 119 | … try: 120 | … conn.close() 121 | … except Exception: | ^^^^^^^^^ 122 | … pass 123 | … conn = ftplib.FTP(host, timeout=120) | S110 `try`-`except`-`pass` detected, consider logging the exception --> quarry/etl/fetch.py:128:13 | 126 | try: 127 | conn.quit() 128 | / except Exception: 129 | | pass | |____________________^ 130 | return results | BLE001 Do not catch blind exception: `Exception` --> quarry/etl/fetch.py:128:20 | 126 | try: 127 | conn.quit() 128 | except Exception: | ^^^^^^^^^ 129 | pass 130 | return results | DTZ005 `datetime.datetime.now()` called without a `tz` argument --> quarry/etl/fetch.py:189:15 | 188 | if dest.exists() and max_age_days is not None: 189 | age = datetime.now() - datetime.fromtimestamp(dest.stat().st_mtime) | ^^^^^^^^^^^^^^ 190 | if age < timedelta(days=max_age_days): 191 | return {"status": "fresh", "path": str(dest), "bytes": dest.stat().st_size} | help: Pass a `datetime.timezone` object to the `tz` parameter DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument --> quarry/etl/fetch.py:189:32 | 188 | if dest.exists() and max_age_days is not None: 189 | age = datetime.now() - datetime.fromtimestamp(dest.stat().st_mtime) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 190 | if age < timedelta(days=max_age_days): 191 | return {"status": "fresh", "path": str(dest), "bytes": dest.stat().st_size} | help: Pass a `datetime.timezone` object to the `tz` parameter DTZ005 `datetime.datetime.now()` called without a `tz` argument --> quarry/etl/fetch.py:247:15 | 246 | if target.exists(): 247 | age = datetime.now() - datetime.fromtimestamp(target.stat().st_mtime) | ^^^^^^^^^^^^^^ 248 | if age < timedelta(days=max_age_days): 249 | return { | help: Pass a `datetime.timezone` object to the `tz` parameter DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument --> quarry/etl/fetch.py:247:32 | 246 | if target.exists(): 247 | age = datetime.now() - datetime.fromtimestamp(target.stat().st_mtime) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 248 | if age < timedelta(days=max_age_days): 249 | return { | help: Pass a `datetime.timezone` object to the `tz` parameter SIM117 Use a single `with` statement with multiple contexts instead of nested `with` statements --> quarry/etl/fetch.py:259:5 | 258 | tmp_target = target.with_suffix(target.suffix + ".tmp") 259 | / with zipfile.ZipFile(zip_path) as zf: 260 | | # Extract only the expected file to a temp path 261 | | with zf.open(expected_file) as src, open(tmp_target, "wb") as dst: | |__________________________________________________________________________^ 262 | while chunk := src.read(65536): 263 | dst.write(chunk) | help: Combine `with` statements BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:109:12 | 107 | try: 108 | tree = lxml_html.fromstring(html_bytes) 109 | except Exception: | ^^^^^^^^^ 110 | return None | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:146:12 | 144 | p.remove(tag) 145 | return " ".join(tree.text_content().split()) 146 | except Exception: | ^^^^^^^^^ 147 | return "" | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:223:12 | 221 | result = converter.convert(stream) 222 | return result.document.export_to_markdown() 223 | except Exception: | ^^^^^^^^^ 224 | return "" | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:288:12 | 286 | result.layer = "FAIL" 287 | 288 | except Exception as e: | ^^^^^^^^^ 289 | result.notes.append(f"error: {e}") 290 | result.layer = "FAIL" | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:342:12 | 340 | result.notes.append(f"unexpected ct: {ct[:40]}") 341 | 342 | except Exception as e: | ^^^^^^^^^ 343 | result.notes.append(f"error: {e}") | S110 `try`-`except`-`pass` detected, consider logging the exception --> quarry/fetch.py:381:21 | 379 | try: 380 | pdf_data.append(await response.body()) 381 | / except Exception: 382 | | pass | |____________________________^ 383 | 384 | page.on("response", intercept_pdf) | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:381:28 | 379 | try: 380 | pdf_data.append(await response.body()) 381 | except Exception: | ^^^^^^^^^ 382 | pass | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:429:20 | 427 | result.notes.append("no PDF found in rendered page") 428 | 429 | except Exception as e: | ^^^^^^^^^ 430 | result.notes.append(f"navigation error: {e}") 431 | finally: | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:434:12 | 432 | await browser.close() 433 | 434 | except Exception as e: | ^^^^^^^^^ 435 | result.notes.append(f"L2 error: {e}") | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:475:12 | 473 | result.notes.append(f"text: {text[:60]!r}") 474 | 475 | except Exception as e: | ^^^^^^^^^ 476 | result.layer = "FAIL" 477 | result.notes.append(f"error: {e}") | BLE001 Do not catch blind exception: `Exception` --> quarry/fetch.py:551:12 | 549 | result.notes.append(f"unpaywall -> {oa_url[:70]}") 550 | 551 | except Exception as e: | ^^^^^^^^^ 552 | result.layer = "FAIL" 553 | result.notes.append(f"unpaywall error: {e}") | SIM102 Use a single `if` statement instead of nested `if` statements --> quarry/fetch.py:580:5 | 578 | # API — Zenodo 579 | r_api = await _zenodo_api(url) 580 | / if r_api is not None: 581 | | if r_api.success: | |_________________________^ 582 | return r_api 583 | # Recognized zenodo record but failed — fall through to L1 | help: Combine `if` statements using `and` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/conftest.py:67:9 | 65 | """Run a command with logging.""" 66 | logger.info(f"[{label}] {' '.join(cmd)}") 67 | r = subprocess.run(cmd, capture_output=True, text=True) | ^^^^^^^^^^^^^^ 68 | if r.stdout.strip(): 69 | for line in r.stdout.strip().split("\n"): | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/conftest.py:164:5 | 162 | ) 163 | # Kill any lingering clickhouse-client processes targeting quarry_test 164 | subprocess.run( | ^^^^^^^^^^^^^^ 165 | ["pkill", "-f", f"clickhouse-client.*{TEST_CH_DATABASE}"], 166 | capture_output=True, | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/test_pipeline.py:276:13 | 274 | out_dir = PARSED_DIR / "oa" 275 | out_dir.mkdir(parents=True, exist_ok=True) 276 | r = subprocess.run( | ^^^^^^^^^^^^^^ 277 | [ 278 | "quarry-parse", | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/test_pipeline.py:295:13 | 293 | out_dir = PARSED_DIR / "pubmed" 294 | out_dir.mkdir(parents=True, exist_ok=True) 295 | r = subprocess.run( | ^^^^^^^^^^^^^^ 296 | [ 297 | "quarry-parse", | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/test_pipeline.py:315:13 | 313 | out_dir.mkdir(parents=True, exist_ok=True) 314 | xml_path = DATA_DIR / "pubmed" / "mesh" / "desc_test.xml" 315 | r = subprocess.run( | ^^^^^^^^^^^^^^ 316 | [ 317 | "quarry-parse", | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/test_pipeline.py:414:13 | 413 | # Verify PG has data 414 | r = subprocess.run( | ^^^^^^^^^^^^^^ 415 | ["psql", settings.pg_conninfo, "-t", "-c", "SELECT count(*) FROM works"], 416 | capture_output=True, | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/test_pipeline.py:424:13 | 423 | # Verify join worked (works_export has PM/iCite enrichment) 424 | r = subprocess.run( | ^^^^^^^^^^^^^^ 425 | [ 426 | "psql", | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/integration/test_pipeline.py:453:17 | 451 | print("\n=== PG table summary ===") 452 | for t in tables: 453 | r = subprocess.run( | ^^^^^^^^^^^^^^ 454 | ["psql", settings.pg_conninfo, "-t", "-c", f"SELECT count(*) FROM {t}"], 455 | capture_output=True, | help: Add explicit `check=False` PLW1510 `subprocess.run` without explicit `check` argument --> tests/unit/test_cli_features.py:17:12 | 15 | def _quarry(*args: str, timeout: int = 60) -> subprocess.CompletedProcess: 16 | """Run quarry CLI command and return result.""" 17 | return subprocess.run( | ^^^^^^^^^^^^^^ 18 | ["quarry", *args], 19 | capture_output=True, | help: Add explicit `check=False` Found 73 errors (21 fixed, 52 remaining). No fixes available (8 hidden fixes can be enabled with the `--unsafe-fixes` option). traversed 171 files emitted 140 files for processing formatted 93 files (7 changed) in 518ms Error: failed to finalise formatting: formatting failures detected