import csv import datetime import decimal import io import importlib import itertools import pathlib import shutil import re import pytest import yaml from import2ledger import importers, strparse from . import DATA_DIR try: load_yaml = yaml.full_load except AttributeError: load_yaml = yaml.load class TestImporters: with pathlib.Path(DATA_DIR, 'imports.yml').open() as yaml_file: test_data = load_yaml(yaml_file) for test in test_data: test['source'] = DATA_DIR / test['source'] module_name, class_name = test['importer'].rsplit('.', 1) module = importlib.import_module('.' + module_name, 'import2ledger.importers') test['importer'] = getattr(module, class_name) @pytest.mark.parametrize('source_path,importer', [ (t['source'], t['importer']) for t in test_data ]) def test_can_import(self, source_path, importer): with source_path.open() as source_file: assert importer.can_import(source_file) @pytest.mark.parametrize('source_path,importer,header_rows,header_cols', [ (t['source'], t['importer'], t['header_rows'], t['header_cols']) for t in test_data if t.get('header_rows') ]) def test_can_import_squared_csv(self, source_path, importer, header_rows, header_cols): # Sometimes when we munge spreadsheets by hand (e.g., to filter by # project) tools like LibreOffice Calc write a "squared" spreadsheet, # where every row has the same length. This test ensures the results # are still recognized for import. with io.StringIO() as squared_file: csv_writer = csv.writer(squared_file) with source_path.open() as source_file: for row in itertools.islice(csv.reader(source_file), header_rows): padding = [None] * (header_cols - len(row)) csv_writer.writerow(row + padding) shutil.copyfileobj(source_file, squared_file) squared_file.seek(0) assert importer.can_import(squared_file) @pytest.mark.parametrize('source_path,import_class,expect_results', [ (t['source'], t['importer'], t['expect']) for t in test_data ]) def test_import(self, source_path, import_class, expect_results): with source_path.open() as source_file: importer = import_class(source_file) for actual, expected in itertools.zip_longest(importer, expect_results): actual['amount'] = strparse.currency_decimal(actual['amount']) assert actual == expected def test_loader(self): all_importers = list(importers.load_all()) for test in self.test_data: assert test['importer'] in all_importers