99from collections .abc import Generator , Iterable , Mapping
1010from contextlib import contextmanager
1111from pathlib import Path
12- from typing import Literal , TextIO , TypeVar
12+ from typing import Literal , TextIO , TypeVar , cast
1313
1414import pandas as pd
15+ import pystow .utils
16+ from pystow .utils import safe_open_reader , safe_open_writer
1517from tqdm .auto import tqdm
1618
1719__all__ = [
2022 "multisetdict" ,
2123 "open_map_tsv" ,
2224 "open_multimap_tsv" ,
23- "open_reader" ,
2425 "safe_open" ,
2526 "safe_open_writer" ,
2627 "write_iterable_tsv" ,
3435Y = TypeVar ("Y" )
3536
3637
37- @contextmanager
38- def open_reader (path : str | Path , sep : str = "\t " ):
39- """Open a file and get a reader for it."""
40- path = Path (path )
41- with safe_open (path , read = True ) as file :
42- yield get_reader (file , sep = sep )
43-
44-
4538def get_reader (x , sep : str = "\t " ):
4639 """Get a :func:`csv.reader` with PyOBO default settings."""
4740 return csv .reader (x , delimiter = sep , quoting = csv .QUOTE_MINIMAL )
@@ -51,18 +44,18 @@ def open_map_tsv(
5144 path : str | Path , * , use_tqdm : bool = False , has_header : bool = True
5245) -> Mapping [str , str ]:
5346 """Load a mapping TSV file into a dictionary."""
54- with safe_open (path , read = True ) as file :
47+ rv = {}
48+ with pystow .utils .safe_open_reader (path ) as reader :
5549 if has_header :
56- next (file ) # throw away header
50+ next (reader ) # throw away header
5751 if use_tqdm :
58- file = tqdm (file , desc = f"loading TSV from { path } " )
59- rv = {}
60- for row in get_reader (file ):
52+ reader = tqdm (reader , desc = f"loading TSV from { path } " )
53+ for row in reader :
6154 if len (row ) != 2 :
6255 logger .warning ("[%s] malformed row can not be put in dict: %s" , path , row )
6356 continue
6457 rv [row [0 ]] = row [1 ]
65- return rv
58+ return rv
6659
6760
6861def open_multimap_tsv (
@@ -72,24 +65,27 @@ def open_multimap_tsv(
7265 has_header : bool = True ,
7366) -> Mapping [str , list [str ]]:
7467 """Load a mapping TSV file that has multiple mappings for each."""
75- return multidict (_help_multimap_tsv (path = path , use_tqdm = use_tqdm , has_header = has_header ))
68+ with _help_multimap_tsv (path = path , use_tqdm = use_tqdm , has_header = has_header ) as file :
69+ return multidict (file )
7670
7771
72+ @contextmanager
7873def _help_multimap_tsv (
7974 path : str | Path ,
8075 * ,
8176 use_tqdm : bool = False ,
8277 has_header : bool = True ,
83- ) -> Iterable [tuple [str , str ]]:
84- with safe_open (path , read = True ) as file :
78+ ) -> Generator [ Iterable [tuple [str , str ]], None , None ]:
79+ with safe_open_reader (path ) as reader :
8580 if has_header :
8681 try :
87- next (file ) # throw away header
82+ next (reader ) # throw away header
8883 except gzip .BadGzipFile as e :
8984 raise ValueError (f"could not open file { path } " ) from e
9085 if use_tqdm :
91- file = tqdm (file , desc = f"loading TSV from { path } " )
92- yield from get_reader (file )
86+ yield tqdm (reader , desc = f"loading TSV from { path } " )
87+ else :
88+ yield cast (Iterable [tuple [str , str ]], reader )
9389
9490
9591def multidict (pairs : Iterable [tuple [X , Y ]]) -> Mapping [X , list [Y ]]:
@@ -156,6 +152,7 @@ def safe_open(
156152 path : str | Path , read : bool , encoding : str | None = None
157153) -> Generator [TextIO , None , None ]:
158154 """Safely open a file for reading or writing text."""
155+ # TODO replace me!
159156 path = Path (path ).expanduser ().resolve ()
160157 mode : Literal ["rt" , "wt" ] = "rt" if read else "wt"
161158 if path .suffix .endswith (".gz" ):
@@ -164,13 +161,3 @@ def safe_open(
164161 else :
165162 with open (path , mode = mode ) as file :
166163 yield file
167-
168-
169- @contextlib .contextmanager
170- def safe_open_writer (f : str | Path | TextIO , * , delimiter : str = "\t " ): # type:ignore
171- """Open a CSV writer, wrapping :func:`csv.writer`."""
172- if isinstance (f , str | Path ):
173- with safe_open (f , read = False ) as file :
174- yield csv .writer (file , delimiter = delimiter )
175- else :
176- yield csv .writer (f , delimiter = delimiter )
0 commit comments