def setUp(self): self.setUpPyfakefs() logging.disable() type_ = models.NotebookType('A4', 210, 297) path = pathlib.Path('/test/notebook.pdf') self.notebook = models.Notebook('notebook', type_, path) self.fs.create_file(str(self.notebook.path)) self.pages_dir = pathlib.Path('~/.local/share/smth/pages').expanduser() self.fs.create_dir(str(self.pages_dir / self.notebook.title)) untitled_notebook = models.Notebook('Untitled', None, None) self.db = mock.MagicMock(**{ 'get_notebook_titles.return_value': [self.notebook.title], 'get_notebook_by_title.return_value': self.notebook, 'get_notebook_by_path.return_value': untitled_notebook, 'notebook_exists.return_value': False, }) self.view = mock.MagicMock(**{ 'ask_for_notebook.return_value': self.notebook.title, }) self.args = mock.MagicMock()
def get_notebook_by_title(self, title: str) -> models.Notebook: """Return notebook with specific title from database. Args: title: A title of a notebook. Raises: db.Error: An error occured executing the query. """ notebook = models.Notebook('', models.NotebookType('', 0, 0), pathlib.Path()) connection = None try: connection = self._connect() cursor = connection.execute(const.SQL_GET_NOTEBOOK_BY_TITLE, (title, )) row = cursor.fetchone() if row: notebook = self._make_notebook_from_row(row) except (sqlite3.Error, Error) as exception: self._handle_error('Failed to get notebook from database', exception) finally: if connection: connection.close() return notebook
def test_scan_paired_pages(self): type_ = models.NotebookType('', 160, 200) type_.pages_paired = True notebook = models.Notebook('', type_, '') pages_queue = collections.deque() pages_queue.extend([1, 2, 3]) scanner_ = scanner.Scanner(self.conf, self.callback) scanner_.scan(notebook, pages_queue) self.callback.on_start.assert_called_once_with('device', [1, 2, 3]) self.callback.on_start_scan_page.assert_has_calls([ mock.call(1), mock.call(2), mock.call(3), ]) page_width_pt = math.ceil(type_.page_width * 150 / 25.4) page_height_pt = math.ceil(type_.page_height * 150 / 25.4) self.image = self.image.crop((0, 0, page_width_pt, page_height_pt)) self.callback.on_finish_scan_page.assert_has_calls([ mock.call(notebook, 1, self.image), mock.call(notebook, 2, self.image), mock.call(notebook, 3, self.image), ]) self.assertEqual(notebook.total_pages, 3)
def setUp(self): self.setUpPyfakefs() logging.disable() self.notebook = models.Notebook('notebook', None, pathlib.Path('/test/path.pdf')) self.db = mock.MagicMock( **{ 'get_notebook_titles.return_value': [self.notebook.title], 'get_notebook_by_title.return_value': self.notebook, }) self.view = mock.MagicMock( **{ 'ask_for_notebook.return_value': self.notebook.title, 'confirm.return_value': True, }) self.fs.create_file(self.notebook.path) pages_root = pathlib.Path('~/.local/share/smth/pages').expanduser() self.pages_dir_path = pages_root / self.notebook.title self.fs.create_dir(self.pages_dir_path) self.args = mock.MagicMock()
def test_scan_nothing_to_scan(self): scanner_ = scanner.Scanner(self.conf, self.callback) notebook = models.Notebook('', models.NotebookType('', 0, 0), '') pages_queue = collections.deque() scanner_.scan(notebook, pages_queue) sane.scan.assert_not_called() self.callback.on_error.assert_called_once()
def _make_notebook_from_row(self, row: sqlite3.Row) -> models.Notebook: type_ = self.get_type_by_id(row['type_id']) notebook = models.Notebook(row['title'], type_, pathlib.Path(row['path'])) notebook.id = row['id'] notebook.total_pages = row['total_pages'] notebook.first_page_number = row['first_page_number'] return notebook
def setUp(self): logging.disable() type_ = models.NotebookType('A4', 210, 297) self.notebook = models.Notebook('Notebook', type_, '/test/path.pdf') self.notebook.total_pages = 3 self.db = mock.MagicMock( **{ 'get_notebook_titles.return_value': [self.notebook.title], 'get_notebook_by_title.return_value': self.notebook, }) self.scan_prefs = { 'device': 'device', 'notebook': self.notebook.title, 'append': '3' } self.view = mock.MagicMock( **{ 'ask_for_notebook.return_value': self.notebook.title, 'ask_for_pages_to_append.return_value': 3, 'ask_for_pages_to_replace.return_value': ['1', '2', '3-4'], }) self.args = mock.MagicMock(**{ 'pdf_only': False, 'set_device': False, }) self.conf = mock.MagicMock(**{ 'scanner_device': None, 'scanner_delay': 0, }) config_patcher = mock.patch('smth.config.Config') config_patcher.start().return_value = self.conf self.addCleanup(config_patcher.stop) self.pdf = mock.MagicMock() fpdf_patcher = mock.patch('fpdf.FPDF') fpdf_patcher.start().return_value = self.pdf self.addCleanup(fpdf_patcher.stop) self.image = mock.MagicMock(size=(100, 200)) self.scanner = mock.MagicMock(**{'scan.return_value': self.image}) sane.init = mock.MagicMock() devices = [ ('pixma:04A9176D_3EBCC9', 'vendor', 'mode', 'scanner device'), ] sane.get_devices = mock.MagicMock(return_value=devices) sane.open = mock.MagicMock(return_value=self.scanner)
def test_scan_keyboard_interrupt(self): sane.open.side_effect = KeyboardInterrupt scanner_ = scanner.Scanner(self.conf, self.callback) notebook = models.Notebook('', models.NotebookType('', 0, 0), '') pages_queue = collections.deque() scanner_.scan(notebook, pages_queue) sane.scan.assert_not_called() self.callback.on_error.assert_called_once() sane.exit.assert_called_once()
def test_total_pages(self): notebook = models.Notebook('title', None, 'path') self.assertEqual(notebook.total_pages, 0) notebook.total_pages = 10 self.assertEqual(notebook.total_pages, 10) notebook.total_pages = 0 self.assertEqual(notebook.total_pages, 0) notebook.total_pages = -10 self.assertEqual(notebook.total_pages, 0)
def setUp(self): self.db = db.DB(self.DB_PATH) # Types for tests self.types = self.db.get_types() type1 = models.NotebookType('Type 1', 100, 200) type2 = models.NotebookType('Type 2', 200, 100) type2.pages_paired = True self.types.append(type1) self.types.append(type2) for type_ in self.types: self.db.save_type(type_) # Notebooks for tests notebook1 = models.Notebook('Notebook 1', type1, '/test/notebook1.pdf') notebook2 = models.Notebook('Notebook 2', type2, '/test/notebook2.pdf') notebook2.total_pages = 10 notebook2.first_page_number = 0 notebook3 = models.Notebook('Notebook 3', type1, '/test/notebook3.pdf') notebook3.first_page_number = 2 self.notebooks = [notebook1, notebook2, notebook3] for notebook in self.notebooks: self.db.save_notebook(notebook)
def test_on_finish(self): type_ = models.NotebookType('', 160, 200) notebook = models.Notebook('', type_, pathlib.Path('/test/path.pdf')) notebook.total_pages = 3 with mock.patch('importlib.util.find_spec') as find_spec: find_spec.return_value = None self.callback.on_finish(notebook) self.db.save_notebook.assert_called_once() self.assertEqual(self.pdf.add_page.call_count, 3) self.assertTrue(notebook.path.exists())
def test_execute_path_already_taken_by_another_notebook(self): path = pathlib.Path('/new/path.pdf') existing_notebook = models.Notebook('another', None, path) self.db.get_notebook_by_path.return_value = existing_notebook answers = { 'title': 'notebook', 'path': str(path), } self.view.ask_for_updated_notebook_properties.return_value = answers with self.assertRaises(SystemExit): commands.UpdateCommand(self.db, self.view).execute(self.args) self.db.save_notebook.assert_not_called()
def test_on_finish_missing_images(self): """Should create PDF but show errors.""" self.pdf.image.side_effect = RuntimeError type_ = models.NotebookType('', 160, 200) notebook = models.Notebook('', type_, pathlib.Path('/test/path.pdf')) notebook.total_pages = 3 with mock.patch('importlib.util.find_spec') as find_spec: find_spec.return_value = None self.callback.on_finish(notebook) self.db.save_notebook.assert_called_once() self.assertEqual(self.pdf.add_page.call_count, 3) self.assertEqual(self.view.show_error.call_count, 3) self.assertTrue(notebook.path.exists())
def execute(self, args: argparse.Namespace) -> None: """Asks user for new notebook info, saves notebook in the database. If path to PDF ends with '.pdf', it is treated as a file. That allows user to specify custom name for notebook's file. Otherwise, treat the path as a directory. The file will be stored in that directory. If the directory does not exist, create it with all parent directories. """ try: type_titles = self._db.get_type_titles() except db.Error as exception: self.exit_with_error(exception) if not type_titles: self._view.show_info("No types found. Please, create a new one:") self._view.show_separator() types.TypesCommand(self._db, self._view).execute(['--create']) type_titles = self._db.get_type_titles() if type_titles: self._view.show_separator() self._view.show_info('Creating a new notebook:') else: self.exit_with_error("No types found. Create one with " "'smth types --create'.") validator = validators.NotebookValidator(self._db) answers = self._view.ask_for_new_notebook_info(type_titles, validator) if not answers: log.info('Creation stopped due to keyboard interrupt') self._view.show_info('Nothing created.') return title = answers['title'] try: type_ = self._db.get_type_by_title(answers['type']) except db.Error as exception: self.exit_with_error(exception) path = pathlib.Path(os.path.expandvars( answers['path'])).expanduser().resolve() if str(path).endswith('.pdf'): if not path.parent.exists(): path.parent.mkdir(parents=True, exist_ok=True) else: if not path.exists(): path.mkdir(parents=True, exist_ok=True) path = path / f'{title}.pdf' if path.exists(): message = ("Notebook not created because " f"'{path}' already exists.") self.exit_with_error(message) notebook = models.Notebook(title, type_, path) notebook.first_page_number = answers['first_page_number'] pdf = fpdf.FPDF() pdf.add_page() try: pdf.output(path) log.info("Created empty PDF at '{path}'") self._db.save_notebook(notebook) except (OSError, db.Error) as exception: self.exit_with_error(exception) pages_root = os.path.expanduser('~/.local/share/smth/pages') pages_dir = os.path.join(pages_root, notebook.title) pathlib.Path(pages_dir).mkdir(parents=True) message = (f"Create notebook '{notebook.title}' " f"of type '{notebook.type.title}' at '{notebook.path}'") log.info(message) self._view.show_info(message)
def test_title(self): self.assertEqual(models.Notebook('Test', None, 'path').title, 'Test') self.assertEqual(models.Notebook('', None, 'path').title, 'Untitled')
def setUp(self): self.notebook = models.Notebook('title', None, 'path')
def test_type(self): type_ = mock.MagicMock() notebook = models.Notebook('title', type_, 'path') self.assertIs(notebook.type, type_) with self.assertRaises(AttributeError): notebook.type = type_
def test_path(self): path = models.Notebook('', None, '/path.pdf').path self.assertEqual(path, '/path.pdf') self.notebook.path = '/test/path/to/file.pdf' self.assertEqual(self.notebook.path, '/test/path/to/file.pdf')
def setUp(self): self.type = models.NotebookType('', 100, 200) self.notebook = models.Notebook('', self.type, '') self.resolution = 150
def test__repr__(self): type_ = mock.MagicMock() type_.title = 'Test Type' notebook = models.Notebook('Test', type_, 'path') expected = "<Notebook 'Test' of type 'Test Type'>" self.assertEqual(notebook.__repr__(), expected)