+class TigerInput:
+ """ Context manager that goes through Tiger input files which may
+ either be in a directory or gzipped together in a tar file.
+ """
+
+ def __init__(self, data_dir: str) -> None:
+ self.tar_handle = None
+ self.files: List[Union[str, tarfile.TarInfo]] = []
+
+ if data_dir.endswith('.tar.gz'):
+ try:
+ self.tar_handle = tarfile.open(data_dir) # pylint: disable=consider-using-with
+ except tarfile.ReadError as err:
+ LOG.fatal("Cannot open '%s'. Is this a tar file?", data_dir)
+ raise UsageError("Cannot open Tiger data file.") from err
+
+ self.files = [i for i in self.tar_handle.getmembers() if i.name.endswith('.csv')]
+ LOG.warning("Found %d CSV files in tarfile with path %s", len(self.files), data_dir)
+ else:
+ files = os.listdir(data_dir)
+ self.files = [os.path.join(data_dir, i) for i in files if i.endswith('.csv')]
+ LOG.warning("Found %d CSV files in path %s", len(self.files), data_dir)
+
+ if not self.files:
+ LOG.warning("Tiger data import selected but no files found at %s", data_dir)
+
+
+ def __enter__(self) -> 'TigerInput':
+ return self
+
+
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
+ if self.tar_handle:
+ self.tar_handle.close()
+ self.tar_handle = None
+
+
+ def next_file(self) -> TextIO:
+ """ Return a file handle to the next file to be processed.
+ Raises an IndexError if there is no file left.
+ """
+ fname = self.files.pop(0)
+
+ if self.tar_handle is not None:
+ extracted = self.tar_handle.extractfile(fname)
+ assert extracted is not None
+ return io.TextIOWrapper(extracted)
+
+ return open(cast(str, fname), encoding='utf-8')
+
+
+ def __len__(self) -> int:
+ return len(self.files)