Source code for scitex_scholar.impact_factor.ImpactFactorEngine

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Timestamp: "2025-10-11 23:58:17 (ywatanabe)"
# File: /home/ywatanabe/proj/scitex_repo/src/scitex/scholar/extra/JournalMetrics.py
# ----------------------------------------
from __future__ import annotations

import os

__FILE__ = "./src/scitex/scholar/extra/JournalMetrics.py"
__DIR__ = os.path.dirname(__FILE__)
# ----------------------------------------

__FILE__ = __file__

"""
Functionalities:
- Retrieves journal impact factors and quartiles
- Provides standalone journal metrics lookup
- Caches results for performance optimization

Dependencies:
- packages:
  - impact_factor

Input:
- Journal names as strings

Output:
- Dictionary containing impact factor and quartile data
"""

"""Imports"""
from functools import lru_cache
from typing import Dict, Optional

from scitex_logging import getLogger

from .jcr.ImpactFactorJCREngine import TABLE as JCR_TABLE
from .jcr.ImpactFactorJCREngine import ImpactFactorJCREngine

logger = getLogger(__name__)

"""Parameters"""

"""Functions & Classes"""


[docs] class ImpactFactorEngine: """ Impact factor service - finds journal metrics from the JCR table. Reads the JCR rows through :class:`ImpactFactorJCREngine`, with an LRU cache in front so repeated lookups of the same journal are free. """
[docs] def __init__(self, cache_size: int = 1000): """Initialize with optional cache size.""" self.name = self.__class__.__name__ self.jcr_engine = ImpactFactorJCREngine() self.get_metrics = lru_cache(maxsize=cache_size)(self._get_metrics_uncached)
[docs] def _get_jcr_year(self) -> str: """Which JCR edition the numbers came from. The edition is stamped on every row when the export is loaded, so it is read rather than inferred. Returns "Source Unknown" when no row carries one -- rows loaded before the field existed, or an empty table. """ try: year = self.jcr_engine.jcr_year if year: return f"JCR {year}" except Exception as exc: logger.debug( f"ImpactFactorEngine: JCR year lookup failed " f"({type(exc).__name__}: {exc}); returning 'Source Unknown'" ) return "Source Unknown"
[docs] def _get_metrics_uncached(self, journal_name: str) -> Optional[Dict]: """Get journal metrics without caching.""" if not self.jcr_engine or not journal_name: return None try: results = self.jcr_engine.search(journal_name) if results: result = results[0] return { "impact_factor": float(result.get("factor") or 0), "quartile": result.get("jcr", "Unknown"), "source": self._get_jcr_year(), } except Exception as exc: # Logged, not swallowed: "no metrics for this journal" and "the # table could not be read at all" are different answers, and the # bare `pass` that used to be here made an unreachable store look # exactly like an unlisted journal. logger.debug( f"ImpactFactorEngine: lookup for {journal_name!r} failed " f"({type(exc).__name__}: {exc})" ) return None
[docs] def get_database_info(self) -> Dict: """Describe where the impact-factor rows live and what is in them.""" if not self.jcr_engine: return {"error": "JCR engine not available"} try: records = self.jcr_engine.records except Exception as exc: return {"error": f"{type(exc).__name__}: {exc}"} info = { "store": self.jcr_engine.store, "table": JCR_TABLE, "total_journals": len(records), "data_year": self._get_jcr_year(), "columns": sorted(records[0]) if records else [], "sample_data": records[:3], } return info
[docs] def get_journal_metrics(journal_name: str) -> Optional[Dict]: """Standalone function to get journal metrics. Parameters ---------- journal_name : str Name of the journal Returns ------- Optional[Dict] Dictionary with impact_factor, quartile, and source keys Example ------- >>> metrics = get_journal_metrics("Nature") >>> print(metrics["impact_factor"]) 64.8 """ engine = ImpactFactorEngine() return engine.get_metrics(journal_name)
if __name__ == "__main__": def main(): """Demonstrate journal metrics lookup.""" metrics_instance = ImpactFactorEngine() # Show where the rows come from print("Impact-factor table") print("=" * 50) db_info = metrics_instance.get_database_info() for key, value in db_info.items(): print(f"{key}: {value}") print("\nJournal Metrics Lookup Demo") print("=" * 50) test_journals = ["Nature", "Science", "Cell"] for journal in test_journals: print(f"\nJournal: {journal}") metrics = get_journal_metrics(journal) if metrics: for key, value in metrics.items(): print(f" {key}: {value}") else: print(" No metrics found") main() # python -m scitex_scholar.extra.JournalMetrics # EOF