From 6f970a41e521523ccc39f29a175751fef41138fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 11 Oct 2016 10:52:27 +0200 Subject: [PATCH] Added utils.find_in_path + unittest --- blender_cloud/utils.py | 33 +++++++++++++++++++ requirements-dev.txt | 8 +++++ .../dir_a1/dir_a2/dir_a3/find_me.txt | 0 .../dir_b1/dir_b2/find_me.txt | 0 tests/test_utils.py | 25 ++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 requirements-dev.txt create mode 100644 tests/test_really_breadth_first/dir_a1/dir_a2/dir_a3/find_me.txt create mode 100644 tests/test_really_breadth_first/dir_b1/dir_b2/find_me.txt create mode 100644 tests/test_utils.py diff --git a/blender_cloud/utils.py b/blender_cloud/utils.py index 635b25e..5512a3a 100644 --- a/blender_cloud/utils.py +++ b/blender_cloud/utils.py @@ -16,6 +16,8 @@ # # ##### END GPL LICENSE BLOCK ##### +import pathlib + def sizeof_fmt(num: int, suffix='B') -> str: """Returns a human-readable size. @@ -29,3 +31,34 @@ def sizeof_fmt(num: int, suffix='B') -> str: num /= 1024 return '%.1f Yi%s' % (num, suffix) + + +def find_in_path(path: pathlib.Path, filename: str) -> pathlib.Path: + """Performs a breadth-first search for the filename. + + Returns the path that contains the file, or None if not found. + """ + + import collections + + # Be lenient on our input type. + if isinstance(path, str): + path = pathlib.Path(path) + + if not path.exists(): + return None + assert path.is_dir() + + to_visit = collections.deque([path]) + while to_visit: + this_path = to_visit.popleft() + + for subpath in this_path.iterdir(): + if subpath.is_dir(): + to_visit.append(subpath) + continue + + if subpath.name == filename: + return subpath + + return None diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..f9c090a --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,8 @@ +-r requirements.txt + +# Primary requirements +pytest==3.0.3 + +# Secondary requirements +py==1.4.31 + diff --git a/tests/test_really_breadth_first/dir_a1/dir_a2/dir_a3/find_me.txt b/tests/test_really_breadth_first/dir_a1/dir_a2/dir_a3/find_me.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_really_breadth_first/dir_b1/dir_b2/find_me.txt b/tests/test_really_breadth_first/dir_b1/dir_b2/find_me.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..865aa69 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,25 @@ +"""Unittests for blender_cloud.utils.""" + +import pathlib +import unittest + +from blender_cloud import utils + + +class FindInPathTest(unittest.TestCase): + def test_nonexistant_path(self): + path = pathlib.Path('/doesnotexistreally') + self.assertFalse(path.exists()) + self.assertIsNone(utils.find_in_path(path, 'jemoeder.blend')) + + def test_really_breadth_first(self): + """A depth-first test might find dir_a1/dir_a2/dir_a3/find_me.txt first.""" + + path = pathlib.Path(__file__).parent / 'test_really_breadth_first' + found = utils.find_in_path(path, 'find_me.txt') + self.assertEqual(path / 'dir_b1' / 'dir_b2' / 'find_me.txt', found) + + def test_nonexistant_file(self): + path = pathlib.Path(__file__).parent / 'test_really_breadth_first' + found = utils.find_in_path(path, 'do_not_find_me.txt') + self.assertEqual(None, found)