@@ -126,6 +126,10 @@ def __init__(self, index_path: Path) -> None:
126126 def _load_index (self ) -> None :
127127 """Load the TSV index file into memory."""
128128 if not self .index_path .exists ():
129+ logger .debug (
130+ "GTDB index not found at %s; species resolution will use NCBI." ,
131+ self .index_path ,
132+ )
129133 return
130134 with open (self .index_path ) as f :
131135 # Skip header line
@@ -314,6 +318,7 @@ def __init__(
314318 self ,
315319 index_dir : Optional [Path ] = None ,
316320 cache_dir : Optional [Path ] = None ,
321+ offline : bool = False ,
317322 ) -> None :
318323 """Initialize the species resolver.
319324
@@ -322,6 +327,8 @@ def __init__(
322327 ~/.nanorunner/indexes/ using the HOME environment variable.
323328 cache_dir: Directory for genome cache. If None, defaults to
324329 ~/.nanorunner/genomes/ using the HOME environment variable.
330+ offline: If True, skip NCBI network lookups and rely only on the
331+ local GTDB index and cached genomes.
325332 """
326333 if index_dir is None :
327334 home = Path (os .environ .get ("HOME" , Path .home ()))
@@ -330,6 +337,7 @@ def __init__(
330337 self ._gtdb = GTDBIndex (index_dir / "gtdb_species.tsv" )
331338 self ._ncbi = NCBIResolver ()
332339 self ._cache = GenomeCache (cache_dir )
340+ self ._offline = offline
333341
334342 def resolve (self , species_name : str ) -> Optional [GenomeRef ]:
335343 """Resolve a species name to a genome reference.
@@ -349,7 +357,9 @@ def resolve(self, species_name: str) -> Optional[GenomeRef]:
349357 if ref is not None :
350358 return ref
351359
352- # Fall back to NCBI
360+ # Fall back to NCBI (skip in offline mode)
361+ if self ._offline :
362+ return None
353363 return self ._ncbi .resolve_by_name (species_name )
354364
355365 def resolve_taxid (self , taxid : int ) -> Optional [GenomeRef ]:
@@ -361,6 +371,8 @@ def resolve_taxid(self, taxid: int) -> Optional[GenomeRef]:
361371 Returns:
362372 GenomeRef if found, None otherwise.
363373 """
374+ if self ._offline :
375+ return None
364376 return self ._ncbi .resolve_by_taxid (taxid )
365377
366378 def suggest (self , partial_name : str ) -> List [str ]:
@@ -384,7 +396,9 @@ def cache(self) -> GenomeCache:
384396 return self ._cache
385397
386398
387- def download_genome (ref : GenomeRef , cache : GenomeCache ) -> Path :
399+ def download_genome (
400+ ref : GenomeRef , cache : GenomeCache , offline : bool = False
401+ ) -> Path :
388402 """Download a genome and cache it.
389403
390404 Uses the NCBI datasets CLI to download the genome sequence for the
@@ -394,19 +408,39 @@ def download_genome(ref: GenomeRef, cache: GenomeCache) -> Path:
394408 Args:
395409 ref: Genome reference specifying the accession to download.
396410 cache: Genome cache instance for storing the downloaded genome.
411+ offline: If True, raise an error instead of downloading when the
412+ genome is not already cached.
397413
398414 Returns:
399415 Path to the cached genome file (gzip compressed).
400416
401417 Raises:
402- RuntimeError: If the download fails or no .fna file is found.
418+ RuntimeError: If the download fails, no .fna file is found,
419+ offline mode is enabled and the genome is not cached, or
420+ the datasets CLI is not installed.
403421 """
404422 # Check cache first
405423 cached_path = cache .get_cached_path (ref )
406424 if cached_path .exists ():
407425 logger .info (f"Using cached genome: { cached_path } " )
408426 return cached_path
409427
428+ # Offline mode: genome must already be cached
429+ if offline :
430+ raise RuntimeError (
431+ f"Genome { ref .accession } ({ ref .name } ) is not cached and "
432+ "offline mode is enabled. Run 'nanorunner download' first "
433+ "to cache the required genomes."
434+ )
435+
436+ # Check that datasets CLI is available before attempting download
437+ if shutil .which ("datasets" ) is None :
438+ raise RuntimeError (
439+ f"Cannot download genome { ref .accession } : "
440+ "the 'datasets' CLI (ncbi-datasets-cli) is not installed. "
441+ "Install with: conda install -c conda-forge ncbi-datasets-cli"
442+ )
443+
410444 # Download via datasets CLI
411445 logger .info (f"Downloading genome: { ref .accession } " )
412446
0 commit comments