<commit_before># -*- coding: latin-1 -*-

"""A Python implemntation of a kd-tree

This package provides a simple implementation of a kd-tree in Python.
https://en.wikipedia.org/wiki/K-d_tree
"""

from __future__ import print_function

import math
from collections import deque

__author__ = 'Stefan Kögl <stefan@skoegl.net>'
__version__ = '0.5'
__website__ = 'https://github.com/stefankoegl/kdtree'
__license__ = 'GNU General Public License v3 or later'

class Node(object):
    """ A Node in a kd-tree

    A tree is represented by its root node, and every node represents
    its subtree"""

    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

    @property
    def is_leaf(self):
        """ Returns True if a Node has no subnodes

        >>> Node().is_leaf
        True

        >>> Node( 1, left=Node(2) ).is_leaf
        False
        """
        return (not self.data) or \
               (all(not bool(c) for c, p in self.children))

    def preorder(self):
        """ iterator for nodes: root, left, right """

        if not self:
            return

        yield self

        if self.left:
            for x in self.left.preorder():
                yield x

        if self.right:
            for x in self.right.preorder():
                yield x

    def inorder(self):
        """ iterator for nodes: left, root, right """

        if not self:
            return

        if self.left:
            for x in self.left.inorder():
                yield x

        yield self

        if self.right:
            for x in self.right.inorder():
                yield x

    def postorder(self):
        """ iterator for nodes: left, right, root """

        if not self:
            return

        if self.left:
            for x in self.left.postorder():
                yield x

        if self.right:
            for x in self.right.postorder():
                yield x

        yield self

    @property
    def children(self):
        """
        Returns an iterator for the non-empty children of the Node

        The children are returned as (Node, pos) tuples where pos is 0 for the
        left subnode and 1 for the right.

        >>> len(list(create(dimensions=2).children))
        0

        >>> len(list(create([ (1, 2) ]).children))
        0

        >>> len(list(create([ (2, 2), (2, 1), (2, 3) ]).children))
        2
        """

        if self.left and self.left.data is not None:
            yield self.left, 0
        if self.right and self.right.data is not None:
            yield self.right, 1

    def set_child(self, index, child):
        """ Sets one of the node's children

        index 0 refers to the left, 1 to the right child """

        if index == 0:
            self.left = child
        else:
            self.right = child

    def height(self):
        """
        Returns height of the (sub)tree, without considering
        empty leaf-nodes

        >>> create(dimensions=2).height()
        0

        >>> create([ (1, 2) ]).height()
        1

        >>> create([ (1, 2), (2, 3) ]).height()
        2
        """

        min_height = int(bool(self))
        return max([min_height] + [c.height()+1 for c, p in self.children])

    def get_child_pos(self, child):
        """ Returns the position if the given child

        If the given node is the left child, 0 is returned. If its the right
        child, 1 is returned. Otherwise None """

        for c, pos in self.children:
            if child == c:
                return pos

    def __repr__(self):
        return '<%(cls)s - %(data)s>' % \
            dict(cls=self.__class__.__name__, data=repr(self.data))

    def __nonzero__(self):
        return self.data is not None

    __bool__ = __nonzero__

    def __eq__(self, other):
        if isinstance(other, tuple):
            return self.data == other
        else:
            return self.data == other.data

def require_axis(f):
    """ Check if the object of the function has axis and sel_axis members """

    def _wrapper(self, *args, **kwargs):
        if None in (self.axis, self.sel_axis):
            raise ValueError('%(func_name) requires the node %(node)s '
                    'to have an axis and a sel_axis function' %
                    dict(func_name=f.__name__, node=repr(self)))

        return f(self, *args, **kwargs)

    return _wrapper

class KDNode(Node):
    """ A Node that contains kd-tree specific data and methods """

    def __init__(self, data=None, left=None, right=None, axis=None,
            sel_axis=None, dimensions=None):
        """ Creates a new node for a kd-tree

        If the node will be used within a tree, the axis and the sel_axis
        function should be supplied.

        sel_axis(axis) is used when creating subnodes of the current node. It
        receives the axis of the parent node and returns the axis of the child
        node. """

        super(KDNode, self).__init__(data, left, right)
        self.axis = axis
        self.sel_axis = sel_axis
        self.dimensions = dimensions

    @require_axis
    def add(self, point):
        """
        Adds a point to the current node or iteratively
        descends to one of its children.

        Users should call add() only to the topmost tree.
        """

        current = self
        while True:
            check_dimensionality([point], dimensions=current.dimensions)

            # Adding has hit an empty leaf-node, add here
            if current.data is None:
                current.data = point
                break

            # split on self.axis, recurse either left or right
            if point[current.axis] < current.data[current.axis]:
                if current.left is None:
                    current.left = current.create_subnode(point)
                    break
                else:
                    current = current.left
                    #self.left.add(point)
            else:
                if current.right is None:
                    current.right = current.create_subnode(point)
                    break
                else:
                    current = current.right

    @require_axis
    def create_subnode(self, data):
        """ Creates a subnode for the current node """

        return self.__class__(data,
                axis=self.sel_axis(self.axis),
                sel_axis=self.sel_axis,
                dimensions=self.dimensions)

    @require_axis
    def find_replacement(self):
        """ Finds a replacement for the current node

        The replacement is returned as a
        (replacement-node, replacements-parent-node) tuple """

        if self.right:
            child, parent = self.right.extreme_child(min, self.axis)
        else:
            child, parent = self.left.extreme_child(max, self.axis)

        return (child, parent if parent is not None else self)

    @require_axis
    def remove(self, point):
        """ Removes the node with the given point from the tree

        Returns the new root node of the (sub)tree """

        # Recursion has reached an empty leaf node, nothing here to delete
        if not self:
            return

        # Recursion has not yet reached the node to be deleted
        if self.data != point:

            # Remove direct subnode
            if self.left and self.left.data == point:
                if self.left.is_leaf:
                    self.left = None

                else:
                    self.left = self.left.remove(point)

            elif self.right and self.right.data == point:
                if self.right.is_leaf:
                    self.right = None

                else:
                    self.right = self.right.remove(point)

            # Recurse to subtrees
            if point[self.axis] <= self.data[self.axis]:
                if self.left:
                    self.left = self.left.remove(point)

            if point[self.axis] >= self.data[self.axis]:
                if self.right:
                    self.right = self.right.remove(point)

            return self

        # we have reached the node to be deleted here

        # deleting a leaf node is trivial
        if self.is_leaf:
            self.data = None
            return self

        # we have to delete a non-leaf node here

        # find a replacement for the node (will be the new subtree-root)
        root, max_p = self.find_replacement()

        pos = max_p.get_child_pos(root)

        # self and root swap positions
        tmp_l, tmp_r = self.left, self.right
        self.left, self.right = root.left, root.right
        root.left, root.right = tmp_l if tmp_l is not root else self, tmp_r if tmp_r is not root else self
        self.axis, root.axis = root.axis, self.axis

        # Special-case if we have chosen a direct child as the replacement
        if max_p is not self:
            max_p.set_child(pos, self)
            max_p.remove(point)

        else:
            root.remove(point)

        return root

    @property
    def is_balanced(self):
        """ Returns True if the (sub)tree is balanced

        The tree is balanced if the heights of both subtrees differ at most by
        1 """

        left_height = self.left.height() if self.left else 0
        right_height = self.right.height() if self.right else 0

        if abs(left_height - right_height) > 1:
            return False

        return all(c.is_balanced for c, _ in self.children)

    def rebalance(self):
        """
        Returns the (possibly new) root of the rebalanced tree
        """

        return create([x.data for x in self.inorder()])

    def axis_dist(self, point, axis):
        """
        Squared distance at the given axis between
        the current Node and the given point
        """
        return math.pow(self.data[axis] - point[axis], 2)

    def dist(self, point):
        """
        Squared distance between the current Node
        and the given point
        """
        r = range(len(self.data))
        return sum([self.axis_dist(point, i) for i in r])

    @require_axis
    def search_nn(self, point, best=None):
        """
        Search the nearest node of the given point

        point must be a location, not a node. The nearest node to the point is
        returned. If a location of an actual node is used, the Node with this
        location will be retuend (not its neighbor) """

        current = self
        while True:
            if best is None:
                best = current

            # consider the current node
            if current.dist(point) < best.dist(point):
                best = current

            # sort the children, nearer one first
            children = iter(sorted(current.children,
                key=lambda c_p: c_p[0].axis_dist(point, current.axis)))

            c1, _ = next(children, (None, None))
            if c1:
                current = c1
                continue

            c2, _ = next(children, (None, None))
            if c2 and current.axis_dist(point, current.axis) < best.dist(point):
                current = c2
                continue

            return best

    @require_axis
    def search_nn_dist(self, point, distance, best=None):
        """
        Search the n nearest nodes of the given point which are within given
        distance

        point must be a location, not a node. A list containing the n nearest
        nodes to the point within the distance will be returned.
        """

        if best is None:
            best = []

        # consider the current node
        if self.dist(point) < distance:
            best.append(self)

        # sort the children, nearer one first (is this really necessairy?)
        children = sorted(self.children, key=lambda c_p1: c_p1[0].dist(point))

        for child, p in children:
            # check if child node needs to be recursed
            if self.axis_dist(point, self.axis) < math.pow(distance, 2):
                child.search_nn_dist(point, distance, best)

        return best

    @require_axis
    def is_valid(self):
        """ Checks recursively if the tree is valid

        It is valid if each node splits correctly """

        if not self:
            return True

        if self.left and self.data[self.axis] < self.left.data[self.axis]:
            return False

        if self.right and self.data[self.axis] > self.right.data[self.axis]:
            return False

        return all(c.is_valid() for c, _ in self.children) or self.is_leaf

    def extreme_child(self, sel_func, axis):
        """ Returns a child of the subtree and its parent

        The child is selected by sel_func which is either min or max
        (or a different function with similar semantics). """

        max_key = lambda child_parent: child_parent[0].data[axis]

        # we don't know our parent, so we include None
        me = [(self, None)] if self else []

        child_max = [c.extreme_child(sel_func, axis) for c, _ in self.children]
        # insert self for unknown parents
        child_max = [(c, p if p is not None else self) for c, p in child_max]

        candidates =  me + child_max

        if not candidates:
            return None, None

        return sel_func(candidates, key=max_key)

def create(point_list=None, dimensions=None, axis=0, sel_axis=None):
    """ Creates a kd-tree from a list of points

    All points in the list must be of the same dimensionality.

    If no point_list is given, an empty tree is created. The number of
    dimensions has to be given instead.

    If both a point_list and dimensions are given, the numbers must agree.

    Axis is the axis on which the root-node should split.

    sel_axis(axis) is used when creating subnodes of a node. It receives the
    axis of the parent node and returns the axis of the child node. """

    if not point_list and not dimensions:
        raise ValueError('either point_list or dimensions must be provided')

    elif point_list:
        dimensions = check_dimensionality(point_list, dimensions)

    # by default cycle through the axis
    sel_axis = sel_axis or (lambda prev_axis: (prev_axis+1) % dimensions)

    if not point_list:
        return KDNode(sel_axis=sel_axis, axis=axis, dimensions=dimensions)

    # Sort point list and choose median as pivot element
    point_list.sort(key=lambda point: point[axis])
    median = len(point_list) // 2

    loc   = point_list[median]
    left  = create(point_list[:median], dimensions, sel_axis(axis))
    right = create(point_list[median + 1:], dimensions, sel_axis(axis))
    return KDNode(loc, left, right, axis=axis, sel_axis=sel_axis)

def check_dimensionality(point_list, dimensions=None):
    dimensions = dimensions or len(point_list[0])
    for p in point_list:
        if len(p) != dimensions:
            raise ValueError('All Points in the point_list must have the same dimensionality')

    return dimensions

def level_order(tree, include_all=False):
    """ Returns an iterator over the tree in level-order

    If include_all is set to True, empty parts of the tree are filled
    with dummy entries and the iterator becomes infinite. """

    q = deque()
    q.append(tree)
    while q:
        node = q.popleft()
        yield node

        if include_all or node.left:
            q.append(node.left or node.__class__())

        if include_all or node.right:
            q.append(node.right or node.__class__())

def visualize(tree, max_level=100, node_width=10, left_padding=5):
    """ Prints the tree to stdout """

    height = min(max_level, tree.height()-1)
    max_width = pow(2, height)

    per_level = 1
    in_level  = 0
    level     = 0

    for node in level_order(tree, include_all=True):

        if in_level == 0:
            print()
            print()
            print(' '*left_padding, end=' ')

        width = int(max_width*node_width/per_level)

        node_str = (str(node.data) if node else '').center(width)
        print(node_str, end=' ')

        in_level += 1

        if in_level == per_level:
            in_level   = 0
            per_level *= 2
            level     += 1

        if level > height:
            break

    print()
    print()
<commit_msg>simplify Node.remove()<commit_after># -*- coding: latin-1 -*-

"""A Python implemntation of a kd-tree

This package provides a simple implementation of a kd-tree in Python.
https://en.wikipedia.org/wiki/K-d_tree
"""

from __future__ import print_function

import math
from collections import deque

__author__ = 'Stefan Kögl <stefan@skoegl.net>'
__version__ = '0.5'
__website__ = 'https://github.com/stefankoegl/kdtree'
__license__ = 'GNU General Public License v3 or later'

class Node(object):
    """ A Node in a kd-tree

    A tree is represented by its root node, and every node represents
    its subtree"""

    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

    @property
    def is_leaf(self):
        """ Returns True if a Node has no subnodes

        >>> Node().is_leaf
        True

        >>> Node( 1, left=Node(2) ).is_leaf
        False
        """
        return (not self.data) or \
               (all(not bool(c) for c, p in self.children))

    def preorder(self):
        """ iterator for nodes: root, left, right """

        if not self:
            return

        yield self

        if self.left:
            for x in self.left.preorder():
                yield x

        if self.right:
            for x in self.right.preorder():
                yield x

    def inorder(self):
        """ iterator for nodes: left, root, right """

        if not self:
            return

        if self.left:
            for x in self.left.inorder():
                yield x

        yield self

        if self.right:
            for x in self.right.inorder():
                yield x

    def postorder(self):
        """ iterator for nodes: left, right, root """

        if not self:
            return

        if self.left:
            for x in self.left.postorder():
                yield x

        if self.right:
            for x in self.right.postorder():
                yield x

        yield self

    @property
    def children(self):
        """
        Returns an iterator for the non-empty children of the Node

        The children are returned as (Node, pos) tuples where pos is 0 for the
        left subnode and 1 for the right.

        >>> len(list(create(dimensions=2).children))
        0

        >>> len(list(create([ (1, 2) ]).children))
        0

        >>> len(list(create([ (2, 2), (2, 1), (2, 3) ]).children))
        2
        """

        if self.left and self.left.data is not None:
            yield self.left, 0
        if self.right and self.right.data is not None:
            yield self.right, 1

    def set_child(self, index, child):
        """ Sets one of the node's children

        index 0 refers to the left, 1 to the right child """

        if index == 0:
            self.left = child
        else:
            self.right = child

    def height(self):
        """
        Returns height of the (sub)tree, without considering
        empty leaf-nodes

        >>> create(dimensions=2).height()
        0

        >>> create([ (1, 2) ]).height()
        1

        >>> create([ (1, 2), (2, 3) ]).height()
        2
        """

        min_height = int(bool(self))
        return max([min_height] + [c.height()+1 for c, p in self.children])

    def get_child_pos(self, child):
        """ Returns the position if the given child

        If the given node is the left child, 0 is returned. If its the right
        child, 1 is returned. Otherwise None """

        for c, pos in self.children:
            if child == c:
                return pos

    def __repr__(self):
        return '<%(cls)s - %(data)s>' % \
            dict(cls=self.__class__.__name__, data=repr(self.data))

    def __nonzero__(self):
        return self.data is not None

    __bool__ = __nonzero__

    def __eq__(self, other):
        if isinstance(other, tuple):
            return self.data == other
        else:
            return self.data == other.data

def require_axis(f):
    """ Check if the object of the function has axis and sel_axis members """

    def _wrapper(self, *args, **kwargs):
        if None in (self.axis, self.sel_axis):
            raise ValueError('%(func_name) requires the node %(node)s '
                    'to have an axis and a sel_axis function' %
                    dict(func_name=f.__name__, node=repr(self)))

        return f(self, *args, **kwargs)

    return _wrapper

class KDNode(Node):
    """ A Node that contains kd-tree specific data and methods """

    def __init__(self, data=None, left=None, right=None, axis=None,
            sel_axis=None, dimensions=None):
        """ Creates a new node for a kd-tree

        If the node will be used within a tree, the axis and the sel_axis
        function should be supplied.

        sel_axis(axis) is used when creating subnodes of the current node. It
        receives the axis of the parent node and returns the axis of the child
        node. """

        super(KDNode, self).__init__(data, left, right)
        self.axis = axis
        self.sel_axis = sel_axis
        self.dimensions = dimensions

    @require_axis
    def add(self, point):
        """
        Adds a point to the current node or iteratively
        descends to one of its children.

        Users should call add() only to the topmost tree.
        """

        current = self
        while True:
            check_dimensionality([point], dimensions=current.dimensions)

            # Adding has hit an empty leaf-node, add here
            if current.data is None:
                current.data = point
                break

            # split on self.axis, recurse either left or right
            if point[current.axis] < current.data[current.axis]:
                if current.left is None:
                    current.left = current.create_subnode(point)
                    break
                else:
                    current = current.left
                    #self.left.add(point)
            else:
                if current.right is None:
                    current.right = current.create_subnode(point)
                    break
                else:
                    current = current.right

    @require_axis
    def create_subnode(self, data):
        """ Creates a subnode for the current node """

        return self.__class__(data,
                axis=self.sel_axis(self.axis),
                sel_axis=self.sel_axis,
                dimensions=self.dimensions)

    @require_axis
    def find_replacement(self):
        """ Finds a replacement for the current node

        The replacement is returned as a
        (replacement-node, replacements-parent-node) tuple """

        if self.right:
            child, parent = self.right.extreme_child(min, self.axis)
        else:
            child, parent = self.left.extreme_child(max, self.axis)

        return (child, parent if parent is not None else self)

    @require_axis
    def remove(self, point):
        """ Removes the node with the given point from the tree

        Returns the new root node of the (sub)tree """

        # Recursion has reached an empty leaf node, nothing here to delete
        if not self:
            return

        # Recursion has not yet reached the node to be deleted
        if self.data != point:

            # Remove direct subnode
            if self.left and self.left.data == point:
                self.left = self.left.remove(point)

            elif self.right and self.right.data == point:
                self.right = self.right.remove(point)

            # Recurse to subtrees
            if point[self.axis] <= self.data[self.axis]:
                if self.left:
                    self.left = self.left.remove(point)

            if point[self.axis] >= self.data[self.axis]:
                if self.right:
                    self.right = self.right.remove(point)

            return self

        # we have reached the node to be deleted here

        # deleting a leaf node is trivial
        if self.is_leaf:
            self.data = None
            return self

        # we have to delete a non-leaf node here

        # find a replacement for the node (will be the new subtree-root)
        root, max_p = self.find_replacement()

        pos = max_p.get_child_pos(root)

        # self and root swap positions
        tmp_l, tmp_r = self.left, self.right
        self.left, self.right = root.left, root.right
        root.left, root.right = tmp_l if tmp_l is not root else self, tmp_r if tmp_r is not root else self
        self.axis, root.axis = root.axis, self.axis

        # Special-case if we have chosen a direct child as the replacement
        if max_p is not self:
            max_p.set_child(pos, self)
            max_p.remove(point)

        else:
            root.remove(point)

        return root

    @property
    def is_balanced(self):
        """ Returns True if the (sub)tree is balanced

        The tree is balanced if the heights of both subtrees differ at most by
        1 """

        left_height = self.left.height() if self.left else 0
        right_height = self.right.height() if self.right else 0

        if abs(left_height - right_height) > 1:
            return False

        return all(c.is_balanced for c, _ in self.children)

    def rebalance(self):
        """
        Returns the (possibly new) root of the rebalanced tree
        """

        return create([x.data for x in self.inorder()])

    def axis_dist(self, point, axis):
        """
        Squared distance at the given axis between
        the current Node and the given point
        """
        return math.pow(self.data[axis] - point[axis], 2)

    def dist(self, point):
        """
        Squared distance between the current Node
        and the given point
        """
        r = range(len(self.data))
        return sum([self.axis_dist(point, i) for i in r])

    @require_axis
    def search_nn(self, point, best=None):
        """
        Search the nearest node of the given point

        point must be a location, not a node. The nearest node to the point is
        returned. If a location of an actual node is used, the Node with this
        location will be retuend (not its neighbor) """

        current = self
        while True:
            if best is None:
                best = current

            # consider the current node
            if current.dist(point) < best.dist(point):
                best = current

            # sort the children, nearer one first
            children = iter(sorted(current.children,
                key=lambda c_p: c_p[0].axis_dist(point, current.axis)))

            c1, _ = next(children, (None, None))
            if c1:
                current = c1
                continue

            c2, _ = next(children, (None, None))
            if c2 and current.axis_dist(point, current.axis) < best.dist(point):
                current = c2
                continue

            return best

    @require_axis
    def search_nn_dist(self, point, distance, best=None):
        """
        Search the n nearest nodes of the given point which are within given
        distance

        point must be a location, not a node. A list containing the n nearest
        nodes to the point within the distance will be returned.
        """

        if best is None:
            best = []

        # consider the current node
        if self.dist(point) < distance:
            best.append(self)

        # sort the children, nearer one first (is this really necessairy?)
        children = sorted(self.children, key=lambda c_p1: c_p1[0].dist(point))

        for child, p in children:
            # check if child node needs to be recursed
            if self.axis_dist(point, self.axis) < math.pow(distance, 2):
                child.search_nn_dist(point, distance, best)

        return best

    @require_axis
    def is_valid(self):
        """ Checks recursively if the tree is valid

        It is valid if each node splits correctly """

        if not self:
            return True

        if self.left and self.data[self.axis] < self.left.data[self.axis]:
            return False

        if self.right and self.data[self.axis] > self.right.data[self.axis]:
            return False

        return all(c.is_valid() for c, _ in self.children) or self.is_leaf

    def extreme_child(self, sel_func, axis):
        """ Returns a child of the subtree and its parent

        The child is selected by sel_func which is either min or max
        (or a different function with similar semantics). """

        max_key = lambda child_parent: child_parent[0].data[axis]

        # we don't know our parent, so we include None
        me = [(self, None)] if self else []

        child_max = [c.extreme_child(sel_func, axis) for c, _ in self.children]
        # insert self for unknown parents
        child_max = [(c, p if p is not None else self) for c, p in child_max]

        candidates =  me + child_max

        if not candidates:
            return None, None

        return sel_func(candidates, key=max_key)

def create(point_list=None, dimensions=None, axis=0, sel_axis=None):
    """ Creates a kd-tree from a list of points

    All points in the list must be of the same dimensionality.

    If no point_list is given, an empty tree is created. The number of
    dimensions has to be given instead.

    If both a point_list and dimensions are given, the numbers must agree.

    Axis is the axis on which the root-node should split.

    sel_axis(axis) is used when creating subnodes of a node. It receives the
    axis of the parent node and returns the axis of the child node. """

    if not point_list and not dimensions:
        raise ValueError('either point_list or dimensions must be provided')

    elif point_list:
        dimensions = check_dimensionality(point_list, dimensions)

    # by default cycle through the axis
    sel_axis = sel_axis or (lambda prev_axis: (prev_axis+1) % dimensions)

    if not point_list:
        return KDNode(sel_axis=sel_axis, axis=axis, dimensions=dimensions)

    # Sort point list and choose median as pivot element
    point_list.sort(key=lambda point: point[axis])
    median = len(point_list) // 2

    loc   = point_list[median]
    left  = create(point_list[:median], dimensions, sel_axis(axis))
    right = create(point_list[median + 1:], dimensions, sel_axis(axis))
    return KDNode(loc, left, right, axis=axis, sel_axis=sel_axis)

def check_dimensionality(point_list, dimensions=None):
    dimensions = dimensions or len(point_list[0])
    for p in point_list:
        if len(p) != dimensions:
            raise ValueError('All Points in the point_list must have the same dimensionality')

    return dimensions

def level_order(tree, include_all=False):
    """ Returns an iterator over the tree in level-order

    If include_all is set to True, empty parts of the tree are filled
    with dummy entries and the iterator becomes infinite. """

    q = deque()
    q.append(tree)
    while q:
        node = q.popleft()
        yield node

        if include_all or node.left:
            q.append(node.left or node.__class__())

        if include_all or node.right:
            q.append(node.right or node.__class__())

def visualize(tree, max_level=100, node_width=10, left_padding=5):
    """ Prints the tree to stdout """

    height = min(max_level, tree.height()-1)
    max_width = pow(2, height)

    per_level = 1
    in_level  = 0
    level     = 0

    for node in level_order(tree, include_all=True):

        if in_level == 0:
            print()
            print()
            print(' '*left_padding, end=' ')

        width = int(max_width*node_width/per_level)

        node_str = (str(node.data) if node else '').center(width)
        print(node_str, end=' ')

        in_level += 1

        if in_level == per_level:
            in_level   = 0
            per_level *= 2
            level     += 1

        if level > height:
            break

    print()
    print()
<|endoftext|>


<commit_before>#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Esto es un script para tratar de romper un passphrase de ecryptfs usando fuerza bruta.

import sys
import pexpect
import datetime
import math

config = {
    "ecryptcomm": "ecryptfs-unwrap-passphrase"
}
inicio = None
final = None
cantpp = 3   # Cantidad de pruebas por punto.
cantpr = 20  # Cantidad de pruebas por reporte.

def probarPalabra(fichpassph, palabra):
    global config
    # print("Probando \"{}\"".format(palabra))
    expdor = pexpect.spawn("{0} {1}" .format(config["ecryptcomm"], fichpassph))
    expdor.expect("Passphrase: ")
    expdor.sendline(palabra)
    resp = expdor.expect(["Error: ", "[a-z0-9]{10,}"])
    if resp == 0:
        # print("Falló la palabra \"{}\"".format(palabra))
        return False
    else:
        # print("La clave \"{}\" fue exitosa.".format(palabra))
        return True

def ataque_diccionario(fichpassph, fuente):
    print("Haciendo el ataque del diccionario")
    # Lee el diccionario.
    roto = False
    with open(fuente, "r") as fich:
        # Prueba cada palabra en el diccionario.
        for linea in fich:
            palabra = linea[:-1].strip()
            roto = probarPalabra(fichpassph, palabra.capitalize())
            if roto:
                print("Entcontré el passphrase la palabra \"{}\"!!".format(palabra))
                break
            roto = probarPalabra(fichpassph, palabra.upper())
            if roto:
                print("Entcontré el passphrase la palabra \"{}\"!!".format(palabra))
                break
            roto = probarPalabra(fichpassph, palabra.lower())
            if roto:
                print("Encontré el passphrase la palabra \"{}\"!!".format(palabra))
                break
        else:
            print("Se probaron todas las palabras disponibles"
                  + " y no se ha podido romper el passphrase")

def ataque_combinaciones(fichpassph, fuente):
    global inicio
    print("Haciendo el ataque de combinaciones de strings")
    partes = []
    contadores = [0]
    combinacion = ""
    roto = False
    cprob = 0
    with open(fuente, "r") as hfuente:
        # Pon todas las lineas de fuente en partes.
        for linea in hfuente:
            valor = linea[:-1].strip()
            partes.append(valor)
    cant = len(partes)
    while not roto:
        # print(contadores)

        combinacion = ""
        # Arma la combinación.
        for i in contadores:
            combinacion += partes[i]
        # Prueba la combinación.
        roto = probarPalabra(fichpassph, combinacion)
        cprob += 1
        if (cprob % cantpp) == 0:
            print(".", end = "", flush = True)
        if (cprob % cantpr) == 0:
            actual = datetime.datetime.now()
            print("\nCantidad: {} Contador: {} Combinacion: \"{}\" Tiempo: {}".format(
                cprob, contadores, combinacion, actual - inicio))
            print("Probando {} combinaciones por minuto".format(
                math.floor(cprob / ((actual - inicio).total_seconds() / 60)) ))
        # Si encontraste la combinación rompe el bucle.
        if roto:
            print("Encontré le passphrase la palabra \"{}\"!!".format(combinacion))
            break
        # Aumenta los contadores.
        i = 0
        # Aumenta el contador 0
        contadores[i] += 1
        # Mientras sea necesario propagar a los siguientes contadores recorrelos.
        while contadores[i] >= len(partes):
            contadores[i] = 0
            if i == (len(contadores) - 1):
                contadores.append(0)
            else:
                i += 1
                contadores[i] += 1
    print("Probé {} combinaciones.".format(cprob))

def main():
    global inicio, final
    # Revisa los argumentos.
    if len(sys.argv) != 3:
        print("El uso correcto es \"romper-ecryptfs.py"
              + " /home/pedro/.ecryptfs/wrapped-passphrase\""
              + " /home/pedro/diccionario.txt")
        sys.exit(1)
    print("Tratando de romper el passpharse {}.".format(sys.argv[1]))
    # toma el tiempo de inicio
    inicio = datetime.datetime.now()
    print("Comenzando a las {}".format(inicio))
    ataque_combinaciones(sys.argv[1], sys.argv[2])
    # toma el tiempo final
    final = datetime.datetime.now()
    # Haz un reporte final del tiempo
    print("Comenzamos a hacer intentos en: {}".format(inicio))
    print("Terminamos en: {}".format(final))
    print("Tomó: {}".format(final - inicio))

if __name__ == "__main__":
    main()
<commit_msg>Ahora romper-ecryptfs.py soporta iniciar desde contadores no 0.<commit_after>#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Esto es un script para tratar de romper un passphrase de ecryptfs usando fuerza bruta.

import sys
import pexpect
import datetime
import math

config = {
    "ecryptcomm": "ecryptfs-unwrap-passphrase"
}
inicio = None
final = None
cantpp = 10   # Cantidad de pruebas por punto.
cantpr = 1000  # Cantidad de pruebas por reporte.

def probarPalabra(fichpassph, palabra):
    global config
    # print("Probando \"{}\"".format(palabra))
    expdor = pexpect.spawn("{0} {1}" .format(config["ecryptcomm"], fichpassph))
    expdor.expect("Passphrase: ")
    expdor.sendline(palabra)
    resp = expdor.expect(["Error: ", "[a-z0-9]{10,}"])
    if resp == 0:
        # print("Falló la palabra \"{}\"".format(palabra))
        return False
    else:
        # print("La clave \"{}\" fue exitosa.".format(palabra))
        return True

def ataque_diccionario(fichpassph, fuente):
    print("Haciendo el ataque del diccionario")
    # Lee el diccionario.
    roto = False
    with open(fuente, "r") as fich:
        # Prueba cada palabra en el diccionario.
        for linea in fich:
            palabra = linea[:-1].strip()
            roto = probarPalabra(fichpassph, palabra.capitalize())
            if roto:
                print("Entcontré el passphrase la palabra \"{}\"!!".format(palabra))
                break
            roto = probarPalabra(fichpassph, palabra.upper())
            if roto:
                print("Entcontré el passphrase la palabra \"{}\"!!".format(palabra))
                break
            roto = probarPalabra(fichpassph, palabra.lower())
            if roto:
                print("Encontré el passphrase la palabra \"{}\"!!".format(palabra))
                break
        else:
            print("Se probaron todas las palabras disponibles"
                  + " y no se ha podido romper el passphrase")

def lee_partes(fuente):
    partes = []
    with open(fuente, "r") as hfuente:
        # Pon todas las lineas de fuente en partes.
        for linea in hfuente:
            valor = linea[:-1].strip().lower()
            partes.append(valor)
    return partes

def elimina_duplicados(partes):
    cont = 0
    seg = 0
    while cont < len(partes):
        seg = cont + 1
        while seg < len(partes):
            if partes[cont] == partes[seg]:
                del(partes[seg])
            else:
                seg += 1
        cont += 1

def ataque_combinaciones(fichpassph, fuente, contadores):
    global inicio
    print("Haciendo el ataque de combinaciones de strings")
    combinacion = ""
    roto = False
    cprob = 0
    partes = lee_partes(fuente)
    # Elimina todas las repeticiones
    elimina_duplicados(partes)
    cant = len(partes)
    print("Probando combinaciones con {} cadenas.".format(cant))
    while not roto:
        # print(contadores)
        combinacion = ""
        # Arma la combinación.
        for i in contadores:
            combinacion += partes[i]
        # Prueba la combinación.
        roto = probarPalabra(fichpassph, combinacion)
        cprob += 1
        if (cprob % cantpp) == 0:
            print(".", end = "", flush = True)
        if (cprob % cantpr) == 0:
            actual = datetime.datetime.now()
            print("\nCantidad: {} Contador: {} Combinacion: \"{}\" Tiempo: {}".format(
                cprob, contadores, combinacion, actual - inicio))
            print("Probando {} combinaciones por minuto".format(
                math.floor(cprob / ((actual - inicio).total_seconds() / 60)) ))
        # Si encontraste la combinación rompe el bucle.
        if roto:
            print("Encontré le passphrase la palabra \"{}\"!!".format(combinacion))
            break
        # Aumenta los contadores.
        i = 0
        # Aumenta el contador 0
        contadores[i] += 1
        # Mientras sea necesario propagar a los siguientes contadores recorrelos.
        while contadores[i] >= len(partes):
            contadores[i] = 0
            if i == (len(contadores) - 1):
                contadores.append(0)
            else:
                i += 1
                contadores[i] += 1
    print("Probé {} combinaciones.".format(cprob))

def main():
    global inicio, final
    contadores = [0]
    # Revisa los argumentos.
    if len(sys.argv) < 3:
        print("El uso correcto es \"romper-ecryptfs.py"
              + " /home/pedro/.ecryptfs/wrapped-passphrase\""
              + " /home/pedro/diccionario.txt")
        sys.exit(1)
    for arg in sys.argv[3:]:
        if arg.startswith("--cont="):
            contadores = [int(parte) for parte in arg[len("--cont="):].split("-")]
            print("Iniciando en Contador {}".format(contadores))
    print("Tratando de romper el passpharse {}.".format(sys.argv[1]))
    # toma el tiempo de inicio
    inicio = datetime.datetime.now()
    print("Comenzando a las {}".format(inicio))
    ataque_combinaciones(sys.argv[1], sys.argv[2], contadores)
    # toma el tiempo final
    final = datetime.datetime.now()
    # Haz un reporte final del tiempo
    print("Comenzamos a hacer intentos en: {}".format(inicio))
    print("Terminamos en: {}".format(final))
    print("Tomó: {}".format(final - inicio))

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before># Copyright 2012 the rootpy developers
# distributed under the terms of the GNU General Public License

from __future__ import absolute_import

import ctypes as C
import os

from functools import wraps

import ROOT
# This one is here because it doesn't trigger finalSetup()
ROOT.PyConfig.IgnoreCommandLineOptions = True

from . import log; log = log[__name__]
from .logger import set_error_handler, python_logging_error_handler
from .logger.magic import DANGER, fix_ipython_startup

if not log["/"].have_handlers():
    # The root logger doesn't have any handlers.
    # Therefore, the application hasn't specified any behaviour, and rootpy
    # uses maximum verbosity.
    log["/"].setLevel(log.NOTSET)

use_rootpy_handler = not os.environ.get('NO_ROOTPY_HANDLER', False)
use_rootpy_magic = not os.environ.get('NO_ROOTPY_MAGIC', False)

if use_rootpy_handler:
    if use_rootpy_magic:
        # See magic module for more details
        DANGER.enabled = True
    else:
        log.debug('logger magic disabled')
        DANGER.enabled = False
    # Show python backtrace if there is a segfault
    log["/ROOT.TUnixSystem.DispatchSignals"].showstack(min_level=log.ERROR)
    orig_error_handler = set_error_handler(python_logging_error_handler)
else:
    log.debug('ROOT error handler disabled')

DICTS_PATH = MODS_PATH = None

_initializations = []
def extra_initialization(fn):
    """
    Function decorator which adds `fn` to the list of functions to be called
    at some point after ROOT has been initialized.
    """
    if initialized:
        fn()
    else:
        _initializations.append(fn)
    return fn

def configure_defaults():
    """
    This function is executed immediately after ROOT's finalSetup
    """
    log.debug("configure_defaults()")

    global initialized
    initialized = True

    if use_rootpy_handler:
        # Need to do it again here, since it is overridden by ROOT.
        set_error_handler(python_logging_error_handler)

    # Activate the storage of the sum of squares of errors by default.
    ROOT.TH1.SetDefaultSumw2(True)
    # Activate use of underflows and overflows in `Fill()` in the
    # computation of statistics (mean value, RMS) by default.
    ROOT.TH1.StatOverflows(True)

    if os.environ.get('ROOTPY_BATCH', False):
        ROOT.gROOT.SetBatch(True)
        log.debug('ROOT is running in batch mode')

    ROOT.gErrorIgnoreLevel = 0

    this_dll = C.CDLL(None)
    try:
        EnableAutoDictionary = C.c_int.in_dll(this_dll, "G__EnableAutoDictionary")
    except ValueError:
        pass
    else:
        # Disable automatic dictionary generation
        EnableAutoDictionary.value = 0

    # TODO(pwaller): idea, `execfile("userdata/initrc.py")` here?
    #                 note: that wouldn't allow the user to override the default
    #                       canvas size, for example.

    for init in _initializations:
        init()

def rp_module_level_in_stack():
    """
    Returns true if we're during a rootpy import
    """
    from traceback import extract_stack
    from rootpy import _ROOTPY_SOURCE_PATH
    modlevel_files = [filename for filename, _, func, _ in extract_stack()
                      if func == "<module>"]

    return any(path.startswith(_ROOTPY_SOURCE_PATH) for path in modlevel_files)

# Check in case the horse has already bolted.
# If initialization has already taken place, we can't wrap it.
if hasattr(ROOT.__class__, "_ModuleFacade__finalSetup"):
    initialized = False

    # Inject our own wrapper in place of ROOT's finalSetup so that we can
    # trigger our default options then, and .

    finalSetup = ROOT.__class__._ModuleFacade__finalSetup
    @wraps(finalSetup)
    def wrapFinalSetup(*args, **kwargs):

        log.debug('finalSetup has been triggered')

        if os.environ.get("ROOTPY_DEBUG", None) and rp_module_level_in_stack():
            # Check to see if we're at module level anywhere in rootpy.
            # If so, that's not ideal.
            l = log["bug"]
            l.showstack()
            l.debug("finalSetup triggered from rootpy at module-level. "
                    "Please report this.")

        # if running in the ATLAS environment suppress a known harmless warning
        if os.environ.get("AtlasVersion", None):
            regex = "^duplicate entry .* vectorbool.dll> for level 0; ignored$"
            c = log["/ROOT.TEnvRec.ChangeValue"].ignore(regex)
            with c:
                result = finalSetup(*args, **kwargs)
        else:
            result = finalSetup(*args, **kwargs)

        configure_defaults()

        return result

    wrapFinalSetup._orig_func = finalSetup

    ROOT.__class__._ModuleFacade__finalSetup = wrapFinalSetup

    if "__IPYTHON__" in __builtins__:
        # ROOT has a bug causing it to print (Bool_t)1 to the console.
        fix_ipython_startup(finalSetup)

else:
    initialized = True
    configure_defaults()
<commit_msg>pep8: defaults.py<commit_after># Copyright 2012 the rootpy developers
# distributed under the terms of the GNU General Public License

from __future__ import absolute_import

import ctypes as C
import os

from functools import wraps

import ROOT
# This one is here because it doesn't trigger finalSetup()
ROOT.PyConfig.IgnoreCommandLineOptions = True

from . import log; log = log[__name__]
from .logger import set_error_handler, python_logging_error_handler
from .logger.magic import DANGER, fix_ipython_startup

if not log["/"].have_handlers():
    # The root logger doesn't have any handlers.
    # Therefore, the application hasn't specified any behaviour, and rootpy
    # uses maximum verbosity.
    log["/"].setLevel(log.NOTSET)

use_rootpy_handler = not os.environ.get('NO_ROOTPY_HANDLER', False)
use_rootpy_magic = not os.environ.get('NO_ROOTPY_MAGIC', False)

if use_rootpy_handler:
    if use_rootpy_magic:
        # See magic module for more details
        DANGER.enabled = True
    else:
        log.debug('logger magic disabled')
        DANGER.enabled = False
    # Show python backtrace if there is a segfault
    log["/ROOT.TUnixSystem.DispatchSignals"].showstack(min_level=log.ERROR)
    orig_error_handler = set_error_handler(python_logging_error_handler)
else:
    log.debug('ROOT error handler disabled')

DICTS_PATH = MODS_PATH = None

_initializations = []

def extra_initialization(fn):
    """
    Function decorator which adds `fn` to the list of functions to be called
    at some point after ROOT has been initialized.
    """
    if initialized:
        fn()
    else:
        _initializations.append(fn)
    return fn

def configure_defaults():
    """
    This function is executed immediately after ROOT's finalSetup
    """
    log.debug("configure_defaults()")

    global initialized
    initialized = True

    if use_rootpy_handler:
        # Need to do it again here, since it is overridden by ROOT.
        set_error_handler(python_logging_error_handler)

    # Activate the storage of the sum of squares of errors by default.
    ROOT.TH1.SetDefaultSumw2(True)
    # Activate use of underflows and overflows in `Fill()` in the
    # computation of statistics (mean value, RMS) by default.
    ROOT.TH1.StatOverflows(True)

    if os.environ.get('ROOTPY_BATCH', False):
        ROOT.gROOT.SetBatch(True)
        log.debug('ROOT is running in batch mode')

    ROOT.gErrorIgnoreLevel = 0

    this_dll = C.CDLL(None)
    try:
        EnableAutoDictionary = C.c_int.in_dll(
            this_dll, "G__EnableAutoDictionary")
    except ValueError:
        pass
    else:
        # Disable automatic dictionary generation
        EnableAutoDictionary.value = 0

    # TODO(pwaller): idea, `execfile("userdata/initrc.py")` here?
    #                note: that wouldn't allow the user to override the default
    #                      canvas size, for example.

    for init in _initializations:
        init()

def rp_module_level_in_stack():
    """
    Returns true if we're during a rootpy import
    """
    from traceback import extract_stack
    from rootpy import _ROOTPY_SOURCE_PATH
    modlevel_files = [filename for filename, _, func, _ in extract_stack()
                      if func == "<module>"]

    return any(path.startswith(_ROOTPY_SOURCE_PATH) for path in modlevel_files)

# Check in case the horse has already bolted.
# If initialization has already taken place, we can't wrap it.
if hasattr(ROOT.__class__, "_ModuleFacade__finalSetup"):
    initialized = False

    # Inject our own wrapper in place of ROOT's finalSetup so that we can
    # trigger our default options then, and .

    finalSetup = ROOT.__class__._ModuleFacade__finalSetup

    @wraps(finalSetup)
    def wrapFinalSetup(*args, **kwargs):

        log.debug('finalSetup has been triggered')

        if os.environ.get("ROOTPY_DEBUG", None) and rp_module_level_in_stack():
            # Check to see if we're at module level anywhere in rootpy.
            # If so, that's not ideal.
            l = log["bug"]
            l.showstack()
            l.debug("finalSetup triggered from rootpy at module-level. "
                    "Please report this.")

        # if running in the ATLAS environment suppress a known harmless warning
        if os.environ.get("AtlasVersion", None):
            regex = "^duplicate entry .* vectorbool.dll> for level 0; ignored$"
            c = log["/ROOT.TEnvRec.ChangeValue"].ignore(regex)
            with c:
                result = finalSetup(*args, **kwargs)
        else:
            result = finalSetup(*args, **kwargs)

        configure_defaults()

        return result

    wrapFinalSetup._orig_func = finalSetup

    ROOT.__class__._ModuleFacade__finalSetup = wrapFinalSetup

    if "__IPYTHON__" in __builtins__:
        # ROOT has a bug causing it to print (Bool_t)1 to the console.
        fix_ipython_startup(finalSetup)

else:
    initialized = True
    configure_defaults()
<|endoftext|>


<commit_before>"""
Provides common classes and functions most users will want access to.

"""

import threadinglocal, sys

class _RequestConfig(object):
    """
    RequestConfig thread-local singleton

    The Routes RequestConfig object is a thread-local singleton that should be initialized by
    the web framework that is utilizing Routes.
    """
    __shared_state = threadinglocal.local()
    __shared_glob = {}

    def __getattr__(self, name):
        if name == 'mapper':
            return self.__shared_glob[name]
        return getattr(self.__shared_state, name)

    def __setattr__(self, name, value):
        """
        If the name is environ, load the wsgi envion with load_wsgi_environ
        and set the environ
        """
        if name == 'environ':
            self.load_wsgi_environ(value)
            return self.__shared_state.__setattr__(name, value)
        elif name == 'mapper':
            self.__shared_glob[name] = value
            return
        return self.__shared_state.__setattr__(name, value)

    def __delattr__(self, name):
        delattr(self.__shared_state, name)

    def load_wsgi_environ(self, environ):
        """
        Load the protocol/server info from the environ and store it.
        Also, match the incoming URL if there's already a mapper, and
        store the resulting match dict in mapper_dict.
        """
        if 'wsgi.scheme' in environ:
            self.__shared_state.protocol = environ['wsgi.scheme']
        if 'PATH_INFO' in environ and hasattr(self, 'mapper'):
            mapper = self.mapper
            path = environ['PATH_INFO']
            self.__shared_state.mapper_dict = mapper.match(path)
        if 'SERVER_NAME' in environ:
            host = environ['SERVER_NAME']
            if environ.get('SERVER_PORT', 80) != 80:
                host += ':' + environ['SERVER_PORT']

def request_config(original=False):
    """
    Returns the Routes RequestConfig object.

    To get the Routes RequestConfig:

    >>> from routes import *
    >>> config = routes.request_config()

    The following attributes must be set on the config object every request:

    mapper
        mapper should be a Mapper instance thats ready for use
    host
        host is the hostname of the webapp
    protocol
        protocol is the protocol of the current request
    mapper_dict
        mapper_dict should be the dict returned by mapper.match()
    redirect
        redirect should be a function that issues a redirect,
        and takes a url as the sole argument
    prefix (optional)
        Set if the application is moved under a URL prefix. Prefix
        will be stripped before matching, and prepended on generation
    environ (optional)
        Set to the WSGI environ for automatic prefix support if the
        webapp is underneath a 'SCRIPT_NAME'

    **Using your own requst local**

    If you have your own request local object that you'd like to use instead of the default
    thread local provided by Routes, you can configure Routes to use it::

        from routes import request_config()
        config = request_config()
        if hasattr(config, 'using_request_local'):
            config.request_local = YourLocalCallable
            config = request_config()

    Once you have configured request_config, its advisable you retrieve it again to get the
    object you wanted. The variable you assign to request_local is assumed to be a callable
    that will get the local config object you wish.

    This example tests for the presence of the 'using_request_local' attribute which will be
    present if you haven't assigned it yet. This way you can avoid repeat assignments of the
    request specific callable.

    Should you want the original object, perhaps to change the callable its using or stop
    this behavior, call request_config(original=True).
    """
    obj = _RequestConfig()
    if hasattr(obj, 'request_local') and original is False:
        return getattr(obj, 'request_local')()
    else:
        obj.using_request_local = False
    return _RequestConfig()

from base import Mapper
from util import url_for, redirect_to
__all__=['Mapper', 'url_for', 'redirect_to', 'request_config']<commit_msg>[svn] Change our environ populating to be a bit more accurate and use the host name when possible<commit_after>"""
Provides common classes and functions most users will want access to.

"""

import threadinglocal, sys

class _RequestConfig(object):
    """
    RequestConfig thread-local singleton

    The Routes RequestConfig object is a thread-local singleton that should be initialized by
    the web framework that is utilizing Routes.
    """
    __shared_state = threadinglocal.local()
    __shared_glob = {}

    def __getattr__(self, name):
        if name == 'mapper':
            return self.__shared_glob[name]
        return getattr(self.__shared_state, name)

    def __setattr__(self, name, value):
        """
        If the name is environ, load the wsgi envion with load_wsgi_environ
        and set the environ
        """
        if name == 'environ':
            self.load_wsgi_environ(value)
            return self.__shared_state.__setattr__(name, value)
        elif name == 'mapper':
            self.__shared_glob[name] = value
            return
        return self.__shared_state.__setattr__(name, value)

    def __delattr__(self, name):
        delattr(self.__shared_state, name)

    def load_wsgi_environ(self, environ):
        """
        Load the protocol/server info from the environ and store it.
        Also, match the incoming URL if there's already a mapper, and
        store the resulting match dict in mapper_dict.
        """
        if environ.get('HTTPS'):
            self.__shared_state.protocol = 'https'
        else:
            self.__shared_state.protocol = 'http'
        if 'PATH_INFO' in environ and hasattr(self, 'mapper'):
            mapper = self.mapper
            path = environ['PATH_INFO']
            self.__shared_state.mapper_dict = mapper.match(path)
        host = environ.get('HTTP_HOST') or environ.get('SERVER_NAME')
        self.__shared_state.host = host.split(':')[0]
        if environ.get('SERVER_PORT', 80) != 80:
            self.__shared_state.host += ':' + environ['SERVER_PORT']

def request_config(original=False):
    """
    Returns the Routes RequestConfig object.

    To get the Routes RequestConfig:

    >>> from routes import *
    >>> config = routes.request_config()

    The following attributes must be set on the config object every request:

    mapper
        mapper should be a Mapper instance thats ready for use
    host
        host is the hostname of the webapp
    protocol
        protocol is the protocol of the current request
    mapper_dict
        mapper_dict should be the dict returned by mapper.match()
    redirect
        redirect should be a function that issues a redirect,
        and takes a url as the sole argument
    prefix (optional)
        Set if the application is moved under a URL prefix. Prefix
        will be stripped before matching, and prepended on generation
    environ (optional)
        Set to the WSGI environ for automatic prefix support if the
        webapp is underneath a 'SCRIPT_NAME'

    **Using your own requst local**

    If you have your own request local object that you'd like to use instead of the default
    thread local provided by Routes, you can configure Routes to use it::

        from routes import request_config()
        config = request_config()
        if hasattr(config, 'using_request_local'):
            config.request_local = YourLocalCallable
            config = request_config()

    Once you have configured request_config, its advisable you retrieve it again to get the
    object you wanted. The variable you assign to request_local is assumed to be a callable
    that will get the local config object you wish.

    This example tests for the presence of the 'using_request_local' attribute which will be
    present if you haven't assigned it yet. This way you can avoid repeat assignments of the
    request specific callable.

    Should you want the original object, perhaps to change the callable its using or stop
    this behavior, call request_config(original=True).
    """
    obj = _RequestConfig()
    if hasattr(obj, 'request_local') and original is False:
        return getattr(obj, 'request_local')()
    else:
        obj.using_request_local = False
    return _RequestConfig()

from base import Mapper
from util import url_for, redirect_to
__all__=['Mapper', 'url_for', 'redirect_to', 'request_config']<|endoftext|>


<commit_before>import os

from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.utils import override_settings

from . import DATA_DIR

class BrowserTest(TestCase):
    def test_browser(self):
        url = reverse('graphite.browser.views.browser')
        response = self.client.get(url)
        self.assertContains(response, 'Graphite Browser')

    def test_header(self):
        url = reverse('graphite.browser.views.header')
        response = self.client.get(url)
        self.assertContains(response, 'Graphite Browser Header')

    @override_settings(INDEX_FILE=os.path.join(DATA_DIR, 'index'))
    def test_search(self):
        url = reverse('graphite.browser.views.search')

        response = self.client.post(url)
        self.assertEqual(response.content, '')

        # simple query
        response = self.client.post(url, {'query': 'collectd'})
        self.assertEqual(response.content.split(',')[0],
                         'collectd.test.df-root.df_complex-free')

        # No match
        response = self.client.post(url, {'query': 'other'})
        self.assertEqual(response.content, '')

        # Multiple terms (OR)
        response = self.client.post(url, {'query': 'midterm shortterm'})
        self.assertEqual(response.content.split(','),
                         ['collectd.test.load.load.midterm',
                          'collectd.test.load.load.shortterm'])
<commit_msg>Add tests for making sure a user is dynamically created<commit_after>import os

from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.utils import override_settings

from . import DATA_DIR

class BrowserTest(TestCase):
    def test_browser(self):
        url = reverse('graphite.browser.views.browser')
        response = self.client.get(url)
        self.assertContains(response, 'Graphite Browser')

    def test_header(self):
        self.assertEqual(User.objects.count(), 0)
        url = reverse('graphite.browser.views.header')
        response = self.client.get(url)
        self.assertContains(response, 'Graphite Browser Header')

        # Graphite has created a default user
        self.assertEqual(User.objects.get().username, 'default')

    @override_settings(INDEX_FILE=os.path.join(DATA_DIR, 'index'))
    def test_search(self):
        url = reverse('graphite.browser.views.search')

        response = self.client.post(url)
        self.assertEqual(response.content, '')

        # simple query
        response = self.client.post(url, {'query': 'collectd'})
        self.assertEqual(response.content.split(',')[0],
                         'collectd.test.df-root.df_complex-free')

        # No match
        response = self.client.post(url, {'query': 'other'})
        self.assertEqual(response.content, '')

        # Multiple terms (OR)
        response = self.client.post(url, {'query': 'midterm shortterm'})
        self.assertEqual(response.content.split(','),
                         ['collectd.test.load.load.midterm',
                          'collectd.test.load.load.shortterm'])
<|endoftext|>


<commit_before>#!/usr/bin/env python
##  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
##
##  Use of this source code is governed by a BSD-style license
##  that can be found in the LICENSE file in the root of the source
##  tree. An additional intellectual property rights grant can be found
##  in the file PATENTS.  All contributing project authors may
##  be found in the AUTHORS file in the root of the source tree.
##
"""Wraps paragraphs of text, preserving manual formatting

This is like fold(1), but has the special convention of not modifying lines
that start with whitespace. This allows you to intersperse blocks with
special formatting, like code blocks, with written prose. The prose will
be wordwrapped, and the manual formatting will be preserved.

 * This won't handle the case of a bulleted (or ordered) list specially, so
   manual wrapping must be done.

Occasionally it's useful to put something with explicit formatting that
doesn't look at all like a block of text inline.

  indicator = has_leading_whitespace(line);
  if (indicator)
    preserve_formatting(line);

The intent is that this docstring would make it through the transform
and still be legible and presented as it is in the source. If additional
cases are handled, update this doc to describe the effect.
"""

__author__ = "jkoleszar@google.com"
import textwrap
import sys

def wrap(text):
    if text:
        return textwrap.fill(text, break_long_words=False) + '\n'
    return ""

def main(fileobj):
    text = ""
    output = ""
    while True:
        line = fileobj.readline()
        if not line:
            break

        if line.lstrip() == line:
            text += line
        else:
            output += wrap(text)
            text=""
            output += line
    output += wrap(text)

    # Replace the file or write to stdout.
    if fileobj == sys.stdin:
        fileobj = sys.stdout
    else:
        fileobj.truncate(0)
    fileobj.write(output)

if __name__ == "__main__":
    if len(sys.argv) > 1:
        main(open(sys.argv[1], "r+"))
    else:
        main(sys.stdin)
<commit_msg>tools/wrap-commit-msg.py: fix file truncation<commit_after>#!/usr/bin/env python
##  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
##
##  Use of this source code is governed by a BSD-style license
##  that can be found in the LICENSE file in the root of the source
##  tree. An additional intellectual property rights grant can be found
##  in the file PATENTS.  All contributing project authors may
##  be found in the AUTHORS file in the root of the source tree.
##
"""Wraps paragraphs of text, preserving manual formatting

This is like fold(1), but has the special convention of not modifying lines
that start with whitespace. This allows you to intersperse blocks with
special formatting, like code blocks, with written prose. The prose will
be wordwrapped, and the manual formatting will be preserved.

 * This won't handle the case of a bulleted (or ordered) list specially, so
   manual wrapping must be done.

Occasionally it's useful to put something with explicit formatting that
doesn't look at all like a block of text inline.

  indicator = has_leading_whitespace(line);
  if (indicator)
    preserve_formatting(line);

The intent is that this docstring would make it through the transform
and still be legible and presented as it is in the source. If additional
cases are handled, update this doc to describe the effect.
"""

__author__ = "jkoleszar@google.com"
import textwrap
import sys

def wrap(text):
    if text:
        return textwrap.fill(text, break_long_words=False) + '\n'
    return ""

def main(fileobj):
    text = ""
    output = ""
    while True:
        line = fileobj.readline()
        if not line:
            break

        if line.lstrip() == line:
            text += line
        else:
            output += wrap(text)
            text=""
            output += line
    output += wrap(text)

    # Replace the file or write to stdout.
    if fileobj == sys.stdin:
        fileobj = sys.stdout
    else:
        fileobj.seek(0)
        fileobj.truncate(0)
    fileobj.write(output)

if __name__ == "__main__":
    if len(sys.argv) > 1:
        main(open(sys.argv[1], "r+"))
    else:
        main(sys.stdin)
<|endoftext|>


<commit_before>import numpy as np

import param
from holoviews import Store, Options, Layout, HoloMap, Histogram, Dimension
from holoviews.operation import TreeOperation

class WeightIsotropy(TreeOperation):
    """
    Computes a histogram of azimuths between the positional
    preferences of pre- and post-synaptic neurons weighted
    by the connection strength and normalized relative to
    the orientation preference.

    Useful for determining whether lateral connection are
    anisotropic along the axis of preferred orientation.
    """

    num_bins = param.Integer(default=20, doc="""
        Number of bins in the histogram.""")

    roi = param.NumericTuple(default=(-0.5, -0.5, 0.5, 0.5), doc="""
        Region of interest supplied as a four-tuple of the
        form (left, bottom, right, top)""")

    projections = param.List(default=[], doc="""
       List of tuples of the form (sheet, projection).""")

    @classmethod
    def _last(cls, obj):
        return obj.last if isinstance(obj, HoloMap) else obj

    def _process(self, tree, key=None):
        layout = Layout()
        for s, p in self.p.projections:
            # Get last element
            orelmnt = self._last(tree.OrientationPreference[s])
            xelmnt  = self._last(tree.XPreference[s])
            yelmnt  = self._last(tree.YPreference[s])

            # If any preference has not been supplied skip analysis
            if any(not o for o in [orelmnt, xelmnt, yelmnt]):
                return Layout()

            # Flatten preferences
            xpref_arr = xelmnt.data.flat
            ypref_arr = yelmnt.data.flat

            # Iterate over CFs in ROI
            l, b, r, t = self.p.roi
            lat_weights = tree.CFs[p]
            azimuths, weights = [], []
            for key, cf in lat_weights[l:r, b:t].items():
                # Get preferences for a particular unit
                unit_angle, unit_x, unit_y = orelmnt[key], xelmnt[key], yelmnt[key]
                weight_arr = cf.situated.data.flat
                weight = weight_arr[weight_arr>0]
                xpref = xpref_arr[weight_arr>0]
                ypref = ypref_arr[weight_arr>0]

                # Compute x/y-preference differences between
                # pre- and post-synaptic neurons
                dx = unit_x - xpref
                dy = unit_y - ypref

                # Compute angle between position preferences
                # of the pre- and post-synaptic neurons
                # Correcting for preferred orientation
                conn_angle = np.arctan2(dy, dx)
                conn_angle[conn_angle<0] += 2*np.pi
                delta = conn_angle - unit_angle
                delta2 = conn_angle - (unit_angle + np.pi)
                delta = np.hstack([delta, delta2])
                delta[delta<0] += 2*np.pi
                weight = np.hstack([weight, weight])
                azimuths.append(delta)
                weights.append(weight)

            # Combine azimuths and weights for all CFs
            azimuths = np.concatenate(azimuths)
            weights = np.concatenate(weights)

            # Compute histogram
            bins, edges = np.histogram(azimuths, range=(0, 2*np.pi),
                                       bins=self.p.num_bins, weights=weights, normed=True)

            # Construct Elements
            label =' '.join([s, p])
            histogram = Histogram(bins, edges, group="Weight Isotropy",
                                  kdims=[Dimension('Azimuth')], label=label)
            layout.WeightIsotropy['_'.join([s, p])] = histogram
        return layout

def circular_dist(a, b, period):
    """
    Returns the distance between a and b (scalars) in a domain with `period` period.
    """
    return np.minimum(np.abs(a - b), period - np.abs(a - b))

class WeightDistribution(TreeOperation):
    """
    Computes histogram of the difference in feature
    preference between pre- and post-synaptic neurons
    weighted by the connection strength between them.
    """

    feature = param.String(default='Orientation', doc="""
       Feature to compute the distribution over""")

    num_bins = param.Integer(default=10, doc="""
       Number of histogram bins.""")

    normalized = param.Boolean(default=False, doc="""
       Whether to normalize the histogram""")

    projections = param.List(default=[], doc="""
       List of tuples of the form (sheet, projection).""")

    weighted = param.Boolean(default=True)

    def _process(self, tree, key=None):
        preferences = tree[self.p.feature+'Preference']
        layout = Layout()
        for s, p in self.p.projections:
            if s not in preferences:
                continue
            featurepref = preferences[s]
            if isinstance(featurepref, HoloMap):
                featurepref = featurepref.last
            feature = featurepref.value_dimensions[0]
            feature_arr = featurepref.data.flat
            cfs = tree.CFs[p]
            deltas, weights = [], []
            for k, cf in cfs.items():
                preferred = featurepref[k]
                weight_arr = cf.situated.data.flat
                feature_slice = feature_arr[weight_arr>0]
                weight_slice = weight_arr[weight_arr>0]
                if feature.cyclic:
                    feature_delta = circular_dist(preferred, feature_slice, feature.range[1])
                else:
                    feature_delta = np.abs(feature_slice-preferred)
                deltas.append(feature_delta)
                weights.append(weight_slice)
            deltas = np.concatenate(deltas)
            weights = np.concatenate(weights)
            bin_range = (0, feature.range[1]/2.) if feature.cyclic else None
            bins, edges = np.histogram(deltas, range=bin_range, bins=self.p.num_bins,
                                       weights=weights, normed=self.p.normalized)
            # Construct Elements
            label = ' '.join([s,p])
            group = '%s Weight Distribution' % self.p.feature
            histogram = Histogram(bins, edges, group=group, label=label,
                                  kdims=[' '.join([self.p.feature, 'Difference'])],
                                  vdims=['Weight'])

            layout.WeightDistribution['_'.join([s,p])] = histogram

        return layout

options = Store.options(backend='matplotlib')
options.Histogram.Weight_Isotropy = Options('plot', projection='polar', show_grid=True)
<commit_msg>Added parameters to control WeightIsotropy analysis<commit_after>import numpy as np

import param
from holoviews import Store, Options, Layout, HoloMap, Histogram, Dimension
from holoviews.operation import TreeOperation

class WeightIsotropy(TreeOperation):
    """
    Computes a histogram of azimuths between the positional
    preferences of pre- and post-synaptic neurons weighted
    by the connection strength and normalized relative to
    the orientation preference.

    Useful for determining whether lateral connection are
    anisotropic along the axis of preferred orientation.
    """

    num_bins = param.Integer(default=20, doc="""
        Number of bins in the histogram.""")

    roi = param.NumericTuple(default=(-0.5, -0.5, 0.5, 0.5), doc="""
        Region of interest supplied as a four-tuple of the
        form (left, bottom, right, top)""")

    projections = param.List(default=[], doc="""
       List of tuples of the form (sheet, projection).""")

    threshold = param.Integer(default=70, doc="""
       Threshold as a percentile of the weight field.""")

    min_dist = param.Number(default=0.1, doc="""
       Minimum distance in sheet coordinates""")

    symmetric = param.Boolean(default=True, doc="""
       Whether to make isotropy symmetric.""")

    @classmethod
    def _last(cls, obj):
        return obj.last if isinstance(obj, HoloMap) else obj

    def _process(self, tree, key=None):
        layout = Layout()
        for s, p in self.p.projections:
            # Get last element
            orelmnt = self._last(tree.OrientationPreference[s])
            selelmnt = self._last(tree.OrientationSelectivity[s])
            xelmnt  = self._last(tree.XPreference[s])
            yelmnt  = self._last(tree.YPreference[s])

            # If any preference has not been supplied skip analysis
            if any(not o for o in [orelmnt, xelmnt, yelmnt]):
                return Layout()

            # Flatten preferences
            xpref_arr = xelmnt.dimension_values(2)
            ypref_arr = yelmnt.dimension_values(2)
            sel_arr = selelmnt.dimension_values(2)

            # Iterate over CFs in ROI
            l, b, r, t = self.p.roi
            lat_weights = tree.CFs[p]
            azimuths, weights = [], []
            for key, cf in lat_weights[l:r, b:t].items():
                # Get preferences for a particular unit
                unit_angle, unit_x, unit_y = orelmnt[key], xelmnt[key], yelmnt[key]
                unit_sel = selelmnt[key]
                weight_arr = cf.situated.dimension_values(2)
                mask = weight_arr>np.percentile(weight_arr, self.p.threshold)
                sel = sel_arr[mask]
                weight = weight_arr[mask] * unit_sel * sel
                xpref = xpref_arr[mask]
                ypref = ypref_arr[mask]

                # Compute x/y-preference differences between
                # pre- and post-synaptic neurons
                dx = xpref - unit_x
                dy = ypref - unit_y
                d = np.sqrt(dx**2 + dy**2)

                # Compute angle between position preferences
                # of the pre- and post-synaptic neurons
                # Correcting for preferred orientation
                conn_angle = np.arctan2(dy, dx)
                delta = conn_angle - unit_angle
                delta[delta<0] += np.pi*2
                delta2 = delta + np.pi
                delta2 %= np.pi*2

                azimuths.append(delta[d>self.p.min_dist])
                weights.append(weight[d>self.p.min_dist])
                if self.p.symmetric:
                    azimuths.append(delta2[d>self.p.min_dist])
                    weights.append(weight[d>self.p.min_dist])

            # Combine azimuths and weights for all CFs
            azimuths = np.concatenate(azimuths)
            weights = np.concatenate(weights)
            # Compute histogram
            bins, edges = np.histogram(azimuths, range=(0, 2*np.pi),
                                       bins=self.p.num_bins, weights=weights, normed=True)

            # Construct Elements
            label =' '.join([s, p])
            histogram = Histogram(bins, edges, group="Weight Isotropy",
                                  kdims=[Dimension('Azimuth')], label=label)
            layout.WeightIsotropy['_'.join([s, p])] = histogram
        return layout

def circular_dist(a, b, period):
    """
    Returns the distance between a and b (scalars) in a domain with `period` period.
    """
    return np.minimum(np.abs(a - b), period - np.abs(a - b))

class WeightDistribution(TreeOperation):
    """
    Computes histogram of the difference in feature
    preference between pre- and post-synaptic neurons
    weighted by the connection strength between them.
    """

    feature = param.String(default='Orientation', doc="""
       Feature to compute the distribution over""")

    num_bins = param.Integer(default=10, doc="""
       Number of histogram bins.""")

    normalized = param.Boolean(default=False, doc="""
       Whether to normalize the histogram""")

    projections = param.List(default=[], doc="""
       List of tuples of the form (sheet, projection).""")

    weighted = param.Boolean(default=True)

    def _process(self, tree, key=None):
        preferences = tree[self.p.feature+'Preference']
        layout = Layout()
        for s, p in self.p.projections:
            if s not in preferences:
                continue
            featurepref = preferences[s]
            if isinstance(featurepref, HoloMap):
                featurepref = featurepref.last
            feature = featurepref.value_dimensions[0]
            feature_arr = featurepref.data.flat
            cfs = tree.CFs[p]
            deltas, weights = [], []
            for k, cf in cfs.items():
                preferred = featurepref[k]
                weight_arr = cf.situated.data.flat
                feature_slice = feature_arr[weight_arr>0]
                weight_slice = weight_arr[weight_arr>0]
                if feature.cyclic:
                    feature_delta = circular_dist(preferred, feature_slice, feature.range[1])
                else:
                    feature_delta = np.abs(feature_slice-preferred)
                deltas.append(feature_delta)
                weights.append(weight_slice)
            deltas = np.concatenate(deltas)
            weights = np.concatenate(weights)
            bin_range = (0, feature.range[1]/2.) if feature.cyclic else None
            bins, edges = np.histogram(deltas, range=bin_range, bins=self.p.num_bins,
                                       weights=weights, normed=self.p.normalized)
            # Construct Elements
            label = ' '.join([s,p])
            group = '%s Weight Distribution' % self.p.feature
            histogram = Histogram(bins, edges, group=group, label=label,
                                  kdims=[' '.join([self.p.feature, 'Difference'])],
                                  vdims=['Weight'])

            layout.WeightDistribution['_'.join([s,p])] = histogram

        return layout

options = Store.options(backend='matplotlib')
options.Histogram.Weight_Isotropy = Options('plot', projection='polar', show_grid=True)
<|endoftext|>


<commit_before>"""
To start Topographica, run './topographica' and not this file.  This
file is used to support that file.

./topographica is generated by the Makefile so we keep as much code
outside so the Makefile remains readable, and changes are easier to
implement.

$Id$
"""

__version__='$Revision$'

import sys, __main__, math

from getopt import getopt,GetoptError
import os
from topo.misc.inlinec import import_weave

BANNER         = """
Welcome to Topographica!

Type help() for interactive help with python, help(topo) for general
information about Topographica, help(commandname) for info on a
specific command, or topo.about() for info on this release, including
licensing information.
"""

global_constants = {'PI':math.pi, 'pi':math.pi, 'Pi':math.pi}

def start(interactive=True):
    """
    Function that will display a banner, import topo into main,
    and change the prompt display.  Since this is part of the topo
    package, the topo.__init__ will already be evaluated when this
    file is imported.
    """
    sys.ps1        = 'Topographica> '

    for (k,v) in global_constants.items():
        exec '%s = %s' % (k,v) in __main__.__dict__

    if interactive:
        print BANNER
        try:
            import readline
        except ImportError:
            print "Module readline not available.\nHistory and completion support disabled."
        else:
        #set up command completion
            import rlcompleter
            readline.parse_and_bind("tab: complete")

### JABHACKALERT!
###
### This file will need to be rewritten nearly entirely, probably by
### me (jbednar), to be simpler and have the necessary features.  It's
### clear that there's no reason to keep it even partially compatible
### with python's own command-line format, because that format is not
### very useful.  In particular, it needs to be rewritten to allow
### Topographica/Python commands to be passed to the interpreter, even
### when a file is also being executed.  The current implementation
### mirrors the Python standard: a file can be read, or a
### command-string parsed, but not both.  We can probably continue to
### pass such arguments, if we require '--' before them.

# All valid Python 2.4 args, plus 'g' for topo.gui.start()
VALID_OPTS     = 'ic:dEhOQ:StuvVW:xm:g'

def generate_cmd_prefix(interactive=True,start_gui=False):
    """
    Since a function call is needed for startup, the parameter on if
    the banner should be displayed must be embedded within the command
    string.
    """
#    if start_gui: interactive = True
    # To deal with a need to double-quote under Windows
    if os.name == 'nt': cmd = '"'
    else: cmd = ''

    # (As of 12/2005) With Python 2.4 compiled and run on Windows XP,
    # trying to import Weave after starting the topo command-line will
    # generate a serious system error.  However, importing weave first
    # does not cause problems.
    try:
        if import_weave:
            import weave
            cmd += 'import weave; '
    except:
        pass

    cmd += 'import topo.misc.commandline; topo.misc.commandline.start(' \
           + str(interactive) + ');'
    if start_gui:
        cmd += ' topo.gui_cmdline_flag = True; import topo.tkgui; topo.tkgui.start();'
    else:
        cmd += ' topo.gui_cmdline_flag = False;'

    if os.name == 'nt': cmd += '"'

    return cmd

def generate_params(argv):
    """
    Read in argv (minus argv[0]!), and rearrange for re-execution.
    Pass along all existing flags as well as possible.  If no -c, peel
    off an argument as the file to evaluate.  If no args, and no -c,
    enter interactive mode by adding a possibly redundant '-i'.
    """
    c_flag = False
    in_opts, in_args = getopt(argv,VALID_OPTS)

    #print 'in_opts:', in_opts, ' in_args:', in_args

    opts = list()                      # Preserve order in a list.
    flags = dict(in_opts)              # Quickly check opts for '-i'
    for (key, val) in in_opts:
        if key == '-c':                # Add prefix string to start of a '-c'
            c_flag = True
            val = generate_cmd_prefix(flags.has_key('-i'),
                                      flags.has_key('-g')) + val
        # Python can't handle a '-g', cut it, but add in a -i, so that
        # the GUI will stay.
        if key != '-g':
            opts.append((key,val))
        else:
            opts.append(('-i',''))

    if not c_flag:                     # Create the '-c' on arg 1 or go interactive.
        if len(in_args) >= 1:
            key = '-c'
	    # Under Windows, assumes the last character from
	    # generate_cmd_prefix is a double-quote that can be cut
	    # off, and then extra commands added.
            if os.name == 'nt':
                val = generate_cmd_prefix(flags.has_key('-i'),
                                          flags.has_key('-g'))[:-1] + 'execfile(\'' + in_args[0] + '\');"'
            else:
                val = generate_cmd_prefix(flags.has_key('-i'),
                                          flags.has_key('-g')) + 'execfile(\'' + in_args[0] + '\');'
            opts.append((key,val))
            in_args = in_args[1:]
        else:
            opts.append(('-i',''))     # Add an '-i' since it's needed with -c.
            opts.append(('-c',generate_cmd_prefix(start_gui=flags.has_key('-g'))))

    args = []
    for each in opts:
        args.append(each[0])
        if each[1] != '': args.append(each[1])
    args = args + in_args
    return args

<commit_msg>Replaced old topographica_script code by the new version that uses Optparse.<commit_after>"""
To start Topographica, run './topographica' and not this file.  This
file is used to support that file.

./topographica is generated by the Makefile so we keep as much code
outside so the Makefile remains readable, and changes are easier to
implement.

$Id$
"""

__version__='$Revision$'

import sys, __main__, math

import os
from optparse import OptionParser
from topo.misc.inlinec import import_weave

BANNER         = """
Welcome to Topographica!

Type help() for interactive help with python, help(topo) for general
information about Topographica, help(commandname) for info on a
specific command, or topo.about() for info on this release, including
licensing information.
"""

global_constants = {'PI':math.pi, 'pi':math.pi, 'Pi':math.pi}

def start(interactive=True):
    """
    Function that will display a banner, import topo into main,
    and change the prompt display.  Since this is part of the topo
    package, the topo.__init__ will already be evaluated when this
    file is imported.
    """
    sys.ps1        = 'Topographica> '

    for (k,v) in global_constants.items():
        exec '%s = %s' % (k,v) in __main__.__dict__

    if interactive:
        print BANNER
        try:
            import readline
        except ImportError:
            print "Module readline not available.\nHistory and completion support disabled."
        else:
        #set up command completion
            import rlcompleter
            readline.parse_and_bind("tab: complete")

# Create the parser.
usage = "usage: topographica ([<option>]:[<filename>])*\n\
where <option> can be one of the following:\n\
-c \"<command>\"\n\
-g\n\
-i\n\
-v\n\
"

topo_parser = OptionParser(usage=usage)

# Defining the options

def getting_filenames(parser):
    """
    Sub-function used to catch any filenames following any options.
    """
    list_command=getattr(parser.values,"commands")
    rargs = parser.rargs
    while rargs:
	arg = rargs[0]
	if ((arg[:2] == "--" and len(arg) > 2) or
            (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
            break
	else:
	    list_command = list_command +  'execfile(\'' + arg + '\');'
	    del rargs[0]
    setattr(parser.values,"commands",list_command)

def g_i_action(option,opt_str,value,parser):
    """callback function for the -g and -i option."""
    setattr(parser.values,option.dest,True)
    getting_filenames(parser)

topo_parser.add_option("-g","--gui",action="callback",callback=g_i_action,dest="gui",default=False,help="enter GUI mode.")
topo_parser.add_option( "-i",action="callback",callback=g_i_action,dest="interactive",default=False,
			help="inspect interactively after running script, and force prompts,\
even if stdin does not appear to be a terminal.")

def c_action(option,opt_str,value,parser):
    """callback function for the -c option."""
    list_command=getattr(parser.values,option.dest)
    list_command +=  value + ";"
    setattr(parser.values,option.dest,list_command)
    getting_filenames(parser)

topo_parser.add_option("-c",action = "callback",callback = c_action,type="string",default='',dest="commands",
		       metavar="\"<command>\"",help="commands passed in as a string and followed by files to be executed.")

def append_to_option_list(option,opt_str,value,parser):
    """callback function for all option without argument."""
    option_list=getattr(parser.values,option.dest)
    option_list.append(opt_str)
    getting_filenames(parser)

topo_parser.add_option("-v","--verbose",action="callback",callback = append_to_option_list,
		       nargs=0, dest="list_option", default = [],help="verbose.")

def generate_params(argv):
    """
    Read in argv (minus argv[0]!), and rearrange for re-execution.
    """

    (option,args) = topo_parser.parse_args(argv)

    # catch the first filenames arguments
    filename_arg = topo_parser.largs
    list_filename = ''
    for filename in filename_arg:
	list_filename +=  'execfile(\'' + filename + '\');'

    # generates the prefixes of cmd and option_list
    cmd, option_list = generate_prefixes(option.gui,option.interactive)
    # add the lists of non-arg options (recognized by python)
    option_list += option.list_option

    # cmd is the command line executed by python
    # option_list is the option without arguments that are recognized by Python

    cmd += list_filename
    cmd += option.commands
    # To deal with a need to double-quote under Windows
    if os.name == 'nt': cmd += '"'
    option_list.append('-c')
    return (option_list + [cmd])

def generate_prefixes(gui,interactive):
    """
    Generate start-up command and options.
    """
    option_list = []
     # To deal with a need to double-quote under Windows
    if os.name == 'nt': cmd = '"'
    else: cmd = ''

    # (As of 12/2005) With Python 2.4 compiled and run on Windows XP,
    # trying to import Weave after starting the topo command-line will
    # generate a serious system error.  However, importing weave first
    # does not cause problems.
    try:
        if import_weave:
            import weave
            cmd += 'import weave; '
    except:
        pass

    cmd += 'import topo.misc.commandline; topo.misc.commandline.start(' \
           + str(interactive) + ');'

    # if -g is on
    if gui:
	cmd += ' topo.gui_cmdline_flag = True; import topo.tkgui; topo.tkgui.start();'
	option_list += ['-i']
    else:
        cmd += ' topo.gui_cmdline_flag = False;'

    # if -i is on
    if interactive:
	option_list += ['-i']

    return cmd, option_list
<|endoftext|>