diff --git a/puren_tonbo/__init__.py b/puren_tonbo/__init__.py index 26f63b8..37a9b45 100644 --- a/puren_tonbo/__init__.py +++ b/puren_tonbo/__init__.py @@ -1106,39 +1106,49 @@ def note_contents_save_native_filename(note_text, filename=None, original_filena folder - if specified (new) filename and original_filename are relative. if missing filename and original_filename are absolute """ # Start - restrictions/checks that should be removed + """ if original_filename is not None: + # then if folder specified, original_filename MUST be absolute path + # then if folder missing , original_filename MUST be relative path raise NotImplementedError('original_filename is not None') #original_filename = unicode_path(original_filename) + """ # End - restrictions/checks that should be removed if handler is None: - raise NotImplementedError('handler is required') + raise NotImplementedError('handler is required') # Idea filename required, then use that to detemine handler + filename_generator_func = None if filename is None: - if folder: - # relative path names for files as given as input to this function - if original_filename: - original_filename = os.path.join(folder, original_filename) # TODO abspath for safety? - folder = os.path.dirname(original_filename) + if original_filename and filename_generator in (None, FILENAME_TIMESTAMP, FILENAME_UUID4): + # do not rename... or they could have passed in the "new name" + filename = original_filename + log.debug('filename is original_filename: %r', filename) else: - # folder not set, so absolute paths given as input to this function - folder = os.path.dirname(original_filename) + if folder: + # relative path names for files as given as input to this function + if original_filename: + original_filename = os.path.join(folder, original_filename) # TODO abspath for safety? + folder = os.path.dirname(original_filename) + else: + # folder not set, so absolute paths given as input to this function + folder = os.path.dirname(original_filename) - validate_filename_generator(filename_generator) - filename_generator_func = filename_generators[filename_generator] - file_extension = handler.extensions[0] # pick the first one - filename_without_path_and_extension = filename_generator_func(note_text) + validate_filename_generator(filename_generator) + filename_generator_func = filename_generators[filename_generator] + file_extension = handler.extensions[0] # pick the first one + filename_without_path_and_extension = filename_generator_func(note_text) - filename = os.path.join(folder, filename_without_path_and_extension + file_extension) - # now check if generated filename already exists, if so need to make unique - unique_counter = 1 - while os.path.exists(filename): - #log.warn('generated filename %r already exists', filename) - unique_part = '(%d)' % unique_counter # match Tombo duplicate names avoidance - filename = os.path.join(folder, filename_without_path_and_extension + unique_part + file_extension) - unique_counter += 1 + filename = os.path.join(folder, filename_without_path_and_extension + file_extension) + # now check if generated filename already exists, if so need to make unique + unique_counter = 1 + while os.path.exists(filename): + #log.warn('generated filename %r already exists', filename) + unique_part = '(%d)' % unique_counter # match Tombo duplicate names avoidance + filename = os.path.join(folder, filename_without_path_and_extension + unique_part + file_extension) + unique_counter += 1 - # TODO handle format conversion (e.g. original text, new encrypted) - log.debug('generated filename: %r', filename) + # TODO handle format conversion (e.g. original text, new encrypted) + log.debug('generated filename: %r', filename) else: filename = unicode_path(filename) @@ -1237,10 +1247,19 @@ def note_contents_save_native_filename(note_text, filename=None, original_filena if backup: if os.path.exists(filename): file_replace(filename, filename + '.bak') # backup existing + elif original_filename and os.path.exists(original_filename): + file_replace(original_filename, original_filename + '.bak') # backup existing + # TODO do the same for original if use_tempfile: file_replace(tmp_out_filename, filename) + # handle rename/delete + if filename_generator_func: + # filename generator was used, have have an old file to cleanup + if original_filename and filename != original_filename and os.path.exists(original_filename): + os.remove(original_filename) + def validate_filename_generator(filename_generator): if filename_generator not in ( FILENAME_TIMESTAMP, @@ -1722,7 +1741,7 @@ def note_contents(self, filename, get_pass=None, dos_newlines=True, return_bytes else: return self.to_string(plain_str) - def note_contents_save(self, note_text, filename=None, original_filename=None, folder=None, get_pass=None, dos_newlines=True, backup=True, filename_generator=FILENAME_FIRSTLINE, handler_class=None): + def note_contents_save(self, note_text, filename=None, original_filename=None, folder=None, get_pass=None, dos_newlines=True, backup=True, use_tempfile=True, filename_generator=FILENAME_FIRSTLINE, handler_class=None): """Save/write/encrypt the notes contents, also see note_contents() for load/read/decrypt FIXME make calls to note_contents_save_filename() function instead @@ -1739,6 +1758,9 @@ def note_contents_save(self, note_text, filename=None, original_filename=None, f See note_contents_save_native_filename() docs TODO refactor, there is code duplication (and some differences) between method note_contents_save() and functions note_contents_save_filename() / note_contents_save_native_filename() """ + # FIXME filename/path validation shold take place first before calling note_contents_save_native_filename() + #return note_contents_save_native_filename(note_text, filename=filename, original_filename=original_filename, folder=folder, handler=handler_class, dos_newlines=dos_newlines, backup=backup, use_tempfile=use_tempfile, note_encoding=self.note_encoding, filename_generator=filename_generator) + # sanity checks if filename is not None and folder is not None: raise NotImplementedError('incompatible/inconsistent filename: %r folder: %r ' % (filename, folder)) @@ -1778,7 +1800,6 @@ def note_contents_save(self, note_text, filename=None, original_filename=None, f filename = self.abspath2relative(native_filename) generated_filename = True - filename = self.unicode_path(filename) fullpath_native_filename = self.native_full_path(filename) if original_filename and filename != original_filename: @@ -1790,13 +1811,19 @@ def note_contents_save(self, note_text, filename=None, original_filename=None, f else: handler = handler_class() + #return note_contents_save_native_filename(note_text, filename=filename, original_filename=original_filename, folder=folder, handler=handler_class, dos_newlines=dos_newlines, backup=backup, use_tempfile=use_tempfile, note_encoding=self.note_encoding, filename_generator=filename_generator) + # filename=fullpath_native_filename + # folder=None + return note_contents_save_native_filename(note_text, filename=fullpath_native_filename, original_filename=original_filename, folder=None, handler=handler, dos_newlines=dos_newlines, backup=backup, use_tempfile=use_tempfile, note_encoding=self.note_encoding, filename_generator=filename_generator) + + # x TODO unicode filename # x TODO handler lookup # TODO handler password pass in - see load code above # TODO original filename and rename plain_str_bytes = self.to_bytes(note_text) - use_tempfile = True # do not offer external control over this + #use_tempfile = True # do not offer external control over this? if use_tempfile: timestamp_now = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') out_file = tempfile.NamedTemporaryFile( diff --git a/puren_tonbo/tests/testsuite.py b/puren_tonbo/tests/testsuite.py index fe9c940..adc731d 100644 --- a/puren_tonbo/tests/testsuite.py +++ b/puren_tonbo/tests/testsuite.py @@ -10,6 +10,7 @@ """ +import glob import os import pdb import sys @@ -615,7 +616,7 @@ def setUpClass(self): def tearDownClass(self): shutil.rmtree(self.data_folder) - def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=None, folder=None, dos_newlines=None, test_password_bytes=None, filename_generator=puren_tonbo.FILENAME_FIRSTLINE, expected_filenames=None): + def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=None, folder=None, dos_newlines=None, test_password_bytes=None, backup=True, use_tempfile=True, filename_generator=puren_tonbo.FILENAME_FIRSTLINE, expected_filenames=None): if not expected_filenames: self.assertTrue(False, 'expected_filenames required... not implemented') test_note_filename = new_filename or expected_filenames[0] @@ -628,6 +629,8 @@ def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=Non kwargs = dict( filename_generator=filename_generator, + backup=backup, + use_tempfile=use_tempfile, ) if dos_newlines is not None: kwargs['dos_newlines'] = dos_newlines @@ -668,6 +671,39 @@ def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=Non if os.path.exists(full_pathname): os.remove(full_pathname) # TODO ignore does not exist errors (only), for now skip attempt + # simple, flat, non-nested cleanup + for filename in glob.glob(os.path.join(folder, '*')): + os.remove(filename) + + def test_filename_gen_one_rename_two_with_password_with_backup(self): + buffer_plain_str = '''two + +file WAS one. + +''' + #pdb.set_trace() + file_extension = self.handler_class.extensions[0] # pick the first one + folder = self.data_folder + note_root = puren_tonbo.FileSystemNotes(folder, self.note_encoding) + note_root.note_contents_save('junk', filename='one' + file_extension, filename_generator=None, get_pass=self.test_password_bytes) + + # NOTE implicit backup + self.do_one_test(buffer_plain_str, original_filename='one' + file_extension, dos_newlines=False, test_password_bytes=self.test_password_bytes, expected_filenames=['two' + file_extension, 'one.txt.bak']) + + def test_filename_gen_one_rename_two_with_password_with_nobackup(self): + buffer_plain_str = '''two + +file WAS one. + +''' + #pdb.set_trace() + file_extension = self.handler_class.extensions[0] # pick the first one + folder = self.data_folder + note_root = puren_tonbo.FileSystemNotes(folder, self.note_encoding) + note_root.note_contents_save('junk', filename='one' + file_extension, filename_generator=None, get_pass=self.test_password_bytes) + + self.do_one_test(buffer_plain_str, original_filename='one' + file_extension, dos_newlines=False, test_password_bytes=self.test_password_bytes, backup=False, expected_filenames=['two' + file_extension]) + def test_filename_gen_one_with_password_already_exist(self): buffer_plain_str = '''one @@ -710,7 +746,7 @@ def test_filename_gen_one_no_password(self): class TestFileSystemNotesWriteFunctionSaveRawPlainText(TestFileSystemNotesWriteClassSaveRawPlainText): - def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=None, folder=None, dos_newlines=None, test_password_bytes=None, filename_generator=puren_tonbo.FILENAME_FIRSTLINE, expected_filenames=None): + def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=None, folder=None, dos_newlines=None, test_password_bytes=None, backup=True, use_tempfile=True, filename_generator=puren_tonbo.FILENAME_FIRSTLINE, expected_filenames=None): if not expected_filenames: self.assertTrue(False, 'expected_filenames required... not implemented') test_note_filename = new_filename or expected_filenames[0] @@ -724,6 +760,8 @@ def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=Non kwargs = dict( filename_generator=filename_generator, + backup=backup, + use_tempfile=use_tempfile, ) if dos_newlines is not None: kwargs['dos_newlines'] = dos_newlines @@ -749,7 +787,9 @@ def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=Non data = note_root.note_contents(test_note_filename, password, dos_newlines=dos_newlines) self.assertEqual(buffer_plain_str, data) + expected_filenames.sort() for (dirname, dirnames, filenames) in os.walk(folder): + filenames.sort() #print(dirname, dirnames, filenames) self.assertEqual((folder, [], expected_filenames), (dirname, dirnames, filenames)) @@ -760,6 +800,10 @@ def do_one_test(self, buffer_plain_str, new_filename=None, original_filename=Non if os.path.exists(full_pathname): os.remove(full_pathname) # TODO ignore does not exist errors (only), for now skip attempt + # simple, flat, non-nested cleanup + for filename in glob.glob(os.path.join(folder, '*')): + os.remove(filename) + class TestFileSystemNotesWriteClassSaveEncryptedChi(TestFileSystemNotesWriteClassSaveRawPlainText): handler_class = puren_tonbo.TomboBlowfish # Tombo chi