Skip to content

Instantly share code, notes, and snippets.

@bebraw
Created January 5, 2010 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bebraw/269659 to your computer and use it in GitHub Desktop.
Save bebraw/269659 to your computer and use it in GitHub Desktop.
import inspect
import imp
import os
import tempfile
from node import TreeNode
class File(TreeNode):
def __init__(self, path=None):
super(File, self).__init__()
self.classes = {}
self.__init_classes(path)
self.__init_structure(path)
def __init_classes(self, path):
with open(path, 'r') as f:
file_content = f.read()
# http://docs.python.org/library/tempfile.html#tempfile.mktemp
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.py')
temp_file.write(file_content)
temp_file.close()
try:
module = imp.load_source('', temp_file.name)
except Exception, e:
print e
module_classes = inspect.getmembers(module, inspect.isclass)
for name, klass in module_classes:
self.classes[name.lower()] = klass
os.unlink(temp_file.name)
os.unlink(temp_file.name + 'c')
def __init_structure(self, path):
if not isinstance(path, str) or not path:
return
current_node = self
parts = path.split('/')
for part in reversed(parts):
current_node.name = part
current_node.parent = File()
current_node = current_node.parent
# -*- coding: utf-8 -*-
class AbstractNode(object):
def _generic_find(self, node_list_name, **kvargs):
found_nodes = self._generic_recursion(node_list_name, kvargs, [], [])
return self._check_found_nodes(found_nodes)
def _generic_recursion(self, node_list_name, search_clauses, found_nodes,
visited_nodes):
visited_nodes.append(self)
nodes = getattr(self, node_list_name)
for node in nodes:
try:
all_match = True
for wanted_attribute, wanted_value in search_clauses.items():
attribute = getattr(node, wanted_attribute)
if attribute != wanted_value:
all_match = False
break
if all_match:
found_nodes.append(node)
except AttributeError:
pass
if node not in visited_nodes:
node._generic_recursion(node_list_name, search_clauses,
found_nodes, visited_nodes)
return found_nodes
def _check_found_nodes(self, found_nodes):
if len(found_nodes) > 0:
return found_nodes[0] if len(found_nodes) == 1 else found_nodes
class Node(AbstractNode):
def __init__(self):
self.children = NodeContainer(self, complementary_items_name='parents')
self.parents = NodeContainer(self, complementary_items_name='children')
def walk(self):
def _walk(nodes):
for node in nodes:
for child in _walk(node.children):
yield child
yield node
yield self
for child_walk_node in _walk(self.children):
yield child_walk_node
def find_parent_with_attribute(self, attribute):
return self._find_first_node_with_attribute('parents', attribute, [])
def _find_first_node_with_attribute(self, node_list_name, attribute,
visited_nodes):
visited_nodes.append(self)
nodes = getattr(self, node_list_name)
for node in nodes:
if hasattr(node, attribute):
return node
if node not in visited_nodes:
return node._find_first_node_with_attribute(node_list_name,
attribute, visited_nodes)
def find_child(self, **kvargs):
return self._generic_find(node_list_name='children', **kvargs)
def find_parent(self, **kvargs):
return self._generic_find(node_list_name='parents', **kvargs)
def find_root(self):
return self._generic_find(node_list_name='parents', parents=[])
class TreeNode(AbstractNode):
def __init__(self):
self.children = NodeContainer(self, complementary_items_name='_parents')
# XXX: this is bit of a hack but at least it allows to use generic
# search
self._parents = NodeContainer(self, complementary_items_name='children')
@property
def parent(self):
return self._parents[0]
@parent.setter
def parent(self, value):
assert len(self._parents) <= 1
if len(self._parents) == 1:
self._parents.remove(self._parents[0])
value.children.append(self)
def find(self, **kvargs):
return self._generic_find(node_list_name='children', **kvargs)
class NodeContainer(list):
def __init__(self, owner, complementary_items_name):
super(NodeContainer, self).__init__()
self.owner = owner
self.complementary_items_name = complementary_items_name
def append(self, *items):
for item in items:
if item not in self:
super(NodeContainer, self).append(item)
complementary_items = getattr(item,
self.complementary_items_name)
complementary_items.append(self.owner)
def remove(self, *items):
for item in items:
if item in self:
super(NodeContainer, self).remove(item)
complementary_items = getattr(item,
self.complementary_items_name)
complementary_items.remove(self.owner)
class PluginLoader:
def load(self, directory):
ret = []
for plugin in directory.children:
plugin_file = plugin.find(name=plugin.name)
plugin_class = plugin_file.classes[plugin.name]
ret.append(plugin_class)
return ret
from mock import Mock, patch, sentinel
from placidity.file import File
def mock_with(mock, file_mock):
mock.return_value = Mock()
mock.return_value.__enter__ = Mock()
mock.return_value.__enter__.return_value = file_mock
mock.return_value.__exit__ = Mock()
def mock_with_read(mock, read_return=sentinel.file_contents):
file_mock = Mock()
file_mock.read.return_value = read_return
mock_with(mock, file_mock)
class TestFile:
@patch('__builtin__.open')
def test_get_file_name(self, open_mock):
mock_with_read(open_mock)
file = File('/path/to/file')
assert file.name == 'file'
@patch('__builtin__.open')
def test_get_file_parent(self, open_mock):
mock_with_read(open_mock)
file = File('/path/to/file')
assert file.parent.name == 'to'
assert file.parent.parent.name == 'path'
@patch('__builtin__.open')
def test_get_directory_children(self, open_mock):
mock_with_read(open_mock)
file = File('/path/to/file')
directory = file.parent
assert directory.children == [file, ]
@patch('__builtin__.open')
def test_find_by_name(self, open_mock):
mock_with_read(open_mock)
file = File('/path/to/file')
directory = file.parent
assert directory.find(name='file') == file
@patch('__builtin__.open')
def test_load_python_file(self, open_mock):
read_return_value = '''
class Bar: flag = True
class Foo: flag = False
'''
mock_with_read(open_mock, read_return_value)
file = File(sentinel.filepath)
assert 'bar' in file.classes
assert file.classes['bar'].flag == True
assert 'foo' in file.classes
assert file.classes['foo'].flag == False
# -*- coding: utf-8 -*-
from placidity.node import Node, TreeNode
class TestNode():
def test_append_children_to_node(self):
node1, node2 = Node(), Node()
node1.children.append(node2)
assert node1.children[0] == node2
assert node2.parents[0] == node1
def test_append_parents_to_node(self):
node1, node2 = Node(), Node()
node1.parents.append(node2)
assert node1.parents[0] == node2
assert node2.children[0] == node1
def test_append_same_node_as_child_and_parent(self):
node1, node2 = Node(), Node()
node1.children.append(node2)
node1.parents.append(node2)
assert node1.children[0] == node2
assert node1.parents[0] == node2
assert node2.children[0] == node1
assert node2.parents[0] == node1
def test_append_same_node_as_child_multiple_times(self):
node1, node2 = Node(), Node()
node1.children.append(node2)
node1.children.append(node2)
node1.children.append(node2)
assert node1.children[0] == node2
assert node2.parents[0] == node1
assert len(node1.children) == 1
assert len(node2.parents) == 1
def test_append_same_node_as_parent_multiple_times(self):
node1, node2 = Node(), Node()
node1.parents.append(node2)
node1.parents.append(node2)
node1.parents.append(node2)
assert node1.parents[0] == node2
assert node2.children[0] == node1
assert len(node1.parents) == 1
assert len(node2.children) == 1
def test_multi_append(self):
node1, node2, node3 = Node(), Node(), Node()
node1.children.append(node2, node3)
assert len(node1.children) == 2
assert node2 in node1.children
assert node3 in node1.children
def test_remove_child_node(self):
node1, node2 = Node(), Node()
node1.children.append(node2)
node1.children.remove(node2)
assert len(node1.children) == 0
assert len(node2.parents) == 0
def test_remove_parent_node(self):
node1, node2 = Node(), Node()
node1.parents.append(node2)
node1.parents.remove(node2)
assert len(node1.parents) == 0
assert len(node2.children) == 0
def test_remove_same_node_multiple_times(self):
node1, node2 = Node(), Node()
node1.parents.append(node2)
node1.parents.remove(node2)
node1.parents.remove(node2)
node1.parents.remove(node2)
assert len(node1.parents) == 0
assert len(node2.children) == 0
def test_multi_remove(self):
node1, node2, node3 = Node(), Node(), Node()
node1.children.append(node2, node3)
node1.children.remove(node2, node3)
assert len(node1.children) == 0
def test_find_immediate_child_node(self):
node1, node2 = Node(), Node()
node2.name = 'node to be found'
node1.children.append(node2)
assert node1.find_child(name='node to be found') == node2
def test_find_child_node_no_results(self):
node1 = Node()
assert node1.find_child(name='just some name') == None
def test_find_child_node_from_node_tree(self):
node1 = Node()
node1a = Node()
node1a1 = Node()
node1a1.color = 'blue'
node1a2 = Node()
node1a2.value = 13
node1b = Node()
node1b1 = Node()
node1b1.find_me = True
node1b1.color = 'blue'
node1.children.append(node1a, node1b)
node1a.children.append(node1a1, node1a2)
node1b.children.append(node1b1)
assert node1.find_child(value=13) == node1a2
assert node1.find_child(find_me=True) == node1b1
assert node1.find_child(color='blue') == [node1a1, node1b1]
def test_find_immediate_parent_node(self):
node1, node2 = Node(), Node()
node2.name = 'node to be found'
node1.parents.append(node2)
assert node1.find_parent(name='node to be found') == node2
def test_find_parent_node_no_results(self):
node1 = Node()
assert node1.find_parent(name='just some name') == None
def test_find_parent_node_from_node_tree(self):
node1 = Node()
node1a = Node()
node1a1 = Node()
node1a1.color = 'blue'
node1a2 = Node()
node1a2.value = 13
node1b = Node()
node1b1 = Node()
node1b1.find_me = True
node1b1.color = 'blue'
node1.parents.append(node1a, node1b)
node1a.parents.append(node1a1, node1a2)
node1b.parents.append(node1b1)
assert node1.find_parent(value=13) == node1a2
assert node1.find_parent(find_me=True) == node1b1
assert node1.find_parent(color='blue') == [node1a1, node1b1]
assert node1.find_parent(find_me=True, color='blue') == node1b1
def test_find_root(self):
node1, node1a, node1b, node1a1 = Node(), Node(), Node(), Node()
node1.children.append(node1a, node1b)
node1a.children.append(node1a1)
assert node1.find_root() == None
assert node1a.find_root() == node1
assert node1b.find_root() == node1
assert node1a1.find_root() == node1
def test_cyclic_find(self):
node1, node2 = Node(), Node()
node1.children.append(node2)
node2.children.append(node1)
assert node1.find_root() == None
assert node2.find_root() == None
def test_find_parent_with_value_name(self):
node1, node2, node3 = Node(), Node(), Node()
node3.attribute_to_find = 'find me'
node1.parents.append(node2)
node2.parents.append(node3)
assert node1.find_parent_with_attribute('attribute_to_find') == node3
def test_walk(self):
node1, node2, node3, node4 = Node(), Node(), Node(), Node()
node5 = Node()
node1.children.append(node2)
node1.children.append(node5)
node2.children.append(node3)
node2.children.append(node4)
result = (node1, node3, node4, node2, node5 )
for i, node in enumerate(node1.walk()):
assert node == result[i], '%s %s %s' % (i, node, result[i])
class TestTreeNode():
def test_set_parent(self):
node1, node2 = TreeNode(), TreeNode()
node1.parent = node2
assert node1.parent == node2
assert node2.children == [node1, ]
def test_set_parent_twice(self):
node1, node2, node3 = TreeNode(), TreeNode(), TreeNode()
node1.parent = node2
node1.parent = node3
assert node2.children == []
assert node3.children == [node1, ]
def test_find(self):
node1, node2, node3 = TreeNode(), TreeNode(), TreeNode()
node2.parent = node1
node3.parent = node1
node2.name = 'foo'
node3.name = 'bar'
assert node1.find(name='foo') == node2
assert node1.find(name='bar') == node3
assert node1.find(name='dummy') == None
assert node2.find(name='foo') == None
from mock import Mock
from placidity.plugin_loader import PluginLoader
class TestPluginLoader:
def test_load_plugins(self):
class Plugin1: pass
class Plugin2: pass
plugin_dir = Mock()
plugin1_dir = self.create_plugin_dir('plugin1', Plugin1)
plugin2_dir = self.create_plugin_dir('plugin2', Plugin2)
plugin_dir.children = (plugin1_dir, plugin2_dir)
plugin_loader = PluginLoader()
assert plugin_loader.load(plugin_dir) == [Plugin1, Plugin2]
def create_plugin_dir(self, name, plugin_class):
plugin_dir = Mock()
plugin_dir.name = name
plugin_dir.children = Mock()
plugin_file = self.create_plugin_file(name, plugin_class)
plugin_dir.find.return_value = plugin_file
return plugin_dir
def create_plugin_file(self, name, klass):
plugin_file = Mock()
plugin_file.classes = {name: klass, }
return plugin_file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment