"""Exchange rate CSV parser.""" import csv from io import StringIO from royalties.constants.error import ERROR_CSV_EMPTY class CSVInputError(Exception): """Generic CSV Data Error.""" def __init__(self, message, line_number): """Create exception.""" self.message = message self.line_number = line_number def __str__(self): """Print exception.""" return 'Line:{} Error: {}'.format(self.line_number, self.message) class CSVParser: """CSV file parser.""" def __init__(self, has_header, delimiter, formatter): """Create parser.""" self.errors = [] self.rows = [] self.has_header = has_header self.delimiter = delimiter self.formatter = formatter self.reader = None self.header_values = [] @classmethod def init_from_standard_format(cls, data, formatter): """Return an instance of parser for data in standard fx format.""" sniffer = csv.Sniffer() dialect = sniffer.sniff(data) has_header = sniffer.has_header(data) return cls( has_header=has_header, delimiter=dialect.delimiter, formatter=formatter ) def parse_string(self, data): """Parse a string csv representation.""" stream = StringIO(data) self.reader = csv.reader(stream, delimiter=self.delimiter) self.iterate_lines() if not self.rows and not self.errors: self.errors.append(ERROR_CSV_EMPTY) def iterate_lines(self): """Iterate through lines.""" for row in self.reader: self.parse_line(row) def parse_line(self, row): """Parse a row of data.""" if self.has_header and self.reader.line_num == 1: self.header_values = row return try: self.rows += self.formatter.format( row, self.reader.line_num, header_values=self.header_values ) except CSVInputError as e: self.errors.append(str(e)) def get_results(self): """Return rows and errors.""" return {'rows': self.rows, 'errors': self.errors}