<commit_before>"""PageRank analysis of graph structure. """
#    Copyright (C) 2004-2011 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.
#    NetworkX:http://networkx.lanl.gov/
import networkx as nx
from networkx.exception import NetworkXError
__author__ = """Aric Hagberg (hagberg@lanl.gov)"""
__all__ = ['pagerank','pagerank_numpy','pagerank_scipy','google_matrix']

def pagerank(G,alpha=0.85,personalization=None,
             max_iter=100,tol=1.0e-8,nstart=None,weight='weight'):
    """Return the PageRank of the nodes in the graph.

    PageRank computes a ranking of the nodes in the graph G based on
    the structure of the incoming links. It was originally designed as
    an algorithm to rank web pages.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float, optional
      Damping parameter for PageRank, default=0.85

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    max_iter : integer, optional
      Maximum number of iterations in power method eigenvalue solver.

    tol : float, optional
      Error tolerance used to check convergence in power method solver.

    nstart : dictionary, optional
      Starting value of PageRank iteration for each node.

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    pagerank : dictionary
       Dictionary of nodes with PageRank as value

    Examples
    --------
    >>> G=nx.DiGraph(nx.path_graph(4))
    >>> pr=nx.pagerank(G,alpha=0.9)

    Notes
    -----
    The eigenvector calculation is done by the power iteration method
    and has no guarantee of convergence.  The iteration will stop
    after max_iter iterations or an error tolerance of
    number_of_nodes(G)*tol has been reached.

    The PageRank algorithm was designed for directed graphs but this
    algorithm does not check if the input graph is directed and will
    execute on undirected graphs by converting each oriented edge in the
    directed graph to two edges.

    See Also
    --------
    pagerank_numpy, pagerank_scipy, google_matrix

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry,
       The PageRank citation ranking: Bringing order to the Web. 1999
       http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf
    """
    if type(G) == nx.MultiGraph or type(G) == nx.MultiDiGraph:
        raise Exception("pagerank() not defined for graphs with multiedges.")

    if len(G) == 0:
        return {}

    if not G.is_directed():
        D=G.to_directed()
    else:
        D=G

    # create a copy in (right) stochastic form
    W=nx.stochastic_graph(D, weight=weight)
    scale=1.0/W.number_of_nodes()

    # choose fixed starting vector if not given
    if nstart is None:
        x=dict.fromkeys(W,scale)
    else:
        x=nstart
        # normalize starting vector to 1
        s=1.0/sum(x.values())
        for k in x: x[k]*=s

    # assign uniform personalization/teleportation vector if not given
    if personalization is None:
        p=dict.fromkeys(W,scale)
    else:
        p=personalization
        # normalize starting vector to 1
        s=1.0/sum(p.values())
        for k in p:
            p[k]*=s
        if set(p)!=set(G):
            raise NetworkXError('Personalization vector '
                                'must have a value for every node')

    # "dangling" nodes, no links out from them
    out_degree=W.out_degree()
    dangle=[n for n in W if out_degree[n]==0.0]
    i=0
    while True: # power iteration: make up to max_iter iterations
        xlast=x
        x=dict.fromkeys(xlast.keys(),0)
        danglesum=alpha*scale*sum(xlast[n] for n in dangle)
        for n in x:
            # this matrix multiply looks odd because it is
            # doing a left multiply x^T=xlast^T*W
            for nbr in W[n]:
                x[nbr]+=alpha*xlast[n]*W[n][nbr][weight]
            x[n]+=danglesum+(1.0-alpha)*p[n]
        # normalize vector
        s=1.0/sum(x.values())
        for n in x:
            x[n]*=s
        # check convergence, l1 norm
        err=sum([abs(x[n]-xlast[n]) for n in x])
        if err < tol:
            break
        if i>max_iter:
            raise NetworkXError('pagerank: power iteration failed to converge '
                                'in %d iterations.'%(i-1))
        i+=1
    return x

def google_matrix(G, alpha=0.85, personalization=None,
                  nodelist=None, weight='weight'):
    """Return the Google matrix of the graph.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float
      The damping factor

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    nodelist : list, optional
      The rows and columns are ordered according to the nodes in nodelist.
      If nodelist is None, then the ordering is produced by G.nodes().

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    A : NumPy matrix
       Google matrix of the graph

    See Also
    --------
    pagerank, pagerank_numpy, pagerank_scipy
    """
    try:
        import numpy as np
    except ImportError:
        raise ImportError(\
            "google_matrix() requires NumPy: http://scipy.org/")
    # choose ordering in matrix
    if personalization is None: # use G.nodes() ordering
        nodelist=G.nodes()
    else:  # use personalization "vector" ordering
        nodelist=personalization.keys()
        if set(nodelist)!=set(G):
            raise NetworkXError('Personalization vector dictionary'
                                'must have a value for every node')
    M=nx.to_numpy_matrix(G,nodelist=nodelist,weight=weight)
    (n,m)=M.shape # should be square
    if n == 0:
        return M
    # add constant to dangling nodes' row
    dangling=np.where(M.sum(axis=1)==0)
    for d in dangling[0]:
        M[d]=1.0/n
    # normalize
    M=M/M.sum(axis=1)
    # add "teleportation"/personalization
    e=np.ones((n))
    if personalization is not None:
        v=np.array(list(personalization.values()),dtype=float)
    else:
        v=e
    v=v/v.sum()
    P=alpha*M+(1-alpha)*np.outer(e,v)
    return P

def pagerank_numpy(G, alpha=0.85, personalization=None, weight='weight'):
    """Return the PageRank of the nodes in the graph.

    PageRank computes a ranking of the nodes in the graph G based on
    the structure of the incoming links. It was originally designed as
    an algorithm to rank web pages.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float, optional
      Damping parameter for PageRank, default=0.85

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    pagerank : dictionary
       Dictionary of nodes with PageRank as value

    Examples
    --------
    >>> G=nx.DiGraph(nx.path_graph(4))
    >>> pr=nx.pagerank_numpy(G,alpha=0.9)

    Notes
    -----
    The eigenvector calculation uses NumPy's interface to the LAPACK
    eigenvalue solvers.  This will be the fastest and most accurate
    for small graphs.

    This implementation works with Multi(Di)Graphs.

    See Also
    --------
    pagerank, pagerank_scipy, google_matrix

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry,
       The PageRank citation ranking: Bringing order to the Web. 1999
       http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf
    """
    try:
        import numpy as np
    except ImportError:
        raise ImportError("pagerank_numpy() requires NumPy: http://scipy.org/")
    if len(G) == 0:
        return {}
    # choose ordering in matrix
    if personalization is None: # use G.nodes() ordering
        nodelist=G.nodes()
    else:  # use personalization "vector" ordering
        nodelist=personalization.keys()
    M=google_matrix(G, alpha, personalization=personalization,
                    nodelist=nodelist, weight=weight)
    # use numpy LAPACK solver
    eigenvalues,eigenvectors=np.linalg.eig(M.T)
    ind=eigenvalues.argsort()
    # eigenvector of largest eigenvalue at ind[-1], normalized
    largest=np.array(eigenvectors[:,ind[-1]]).flatten().real
    norm=float(largest.sum())
    centrality=dict(zip(nodelist,map(float,largest/norm)))
    return centrality

def pagerank_scipy(G, alpha=0.85, personalization=None,
                   max_iter=100, tol=1.0e-6, weight='weight'):
    """Return the PageRank of the nodes in the graph.

    PageRank computes a ranking of the nodes in the graph G based on
    the structure of the incoming links. It was originally designed as
    an algorithm to rank web pages.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float, optional
      Damping parameter for PageRank, default=0.85

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    max_iter : integer, optional
      Maximum number of iterations in power method eigenvalue solver.

    tol : float, optional
      Error tolerance used to check convergence in power method solver.

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    pagerank : dictionary
       Dictionary of nodes with PageRank as value

    Examples
    --------
    >>> G=nx.DiGraph(nx.path_graph(4))
    >>> pr=nx.pagerank_scipy(G,alpha=0.9)

    Notes
    -----
    The eigenvector calculation uses power iteration with a SciPy
    sparse matrix representation.

    See Also
    --------
    pagerank, pagerank_numpy, google_matrix

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry,
       The PageRank citation ranking: Bringing order to the Web. 1999
       http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf
    """
    try:
        import scipy.sparse
    except ImportError:
        raise ImportError("pagerank_scipy() requires SciPy: http://scipy.org/")
    if len(G) == 0:
        return {}
    # choose ordering in matrix
    if personalization is None: # use G.nodes() ordering
        nodelist=G.nodes()
    else:  # use personalization "vector" ordering
        nodelist=personalization.keys()
    M=nx.to_scipy_sparse_matrix(G,nodelist=nodelist,weight=weight,dtype='f')
    (n,m)=M.shape # should be square
    S=scipy.array(M.sum(axis=1)).flatten()
#    for i, j, v in zip( *scipy.sparse.find(M) ):
#        M[i,j] = v / S[i]
    S[S>0] = 1.0 / S[S>0]
    Q = scipy.sparse.spdiags(S.T, 0, *M.shape, format='csr')
    M = Q * M
    x=scipy.ones((n))/n  # initial guess
    dangle=scipy.array(scipy.where(M.sum(axis=1)==0,1.0/n,0)).flatten()
    # add "teleportation"/personalization
    if personalization is not None:
        v=scipy.array(list(personalization.values()),dtype=float)
        v=v/v.sum()
    else:
        v=x
    i=0
    while i <= max_iter:
        # power iteration: make up to max_iter iterations
        xlast=x
        x=alpha*(x*M+scipy.dot(dangle,xlast))+(1-alpha)*v
        x=x/x.sum()
        # check convergence, l1 norm
        err=scipy.absolute(x-xlast).sum()
        if err < n*tol:
            return dict(zip(nodelist,map(float,x)))
        i+=1
    raise NetworkXError('pagerank_scipy: power iteration failed to converge'
                        'in %d iterations.'%(i+1))

# fixture for nose tests
def setup_module(module):
    from nose import SkipTest
    try:
        import numpy
    except:
        raise SkipTest("NumPy not available")
    try:
        import scipy
    except:
        raise SkipTest("SciPy not available")
<commit_msg>Fix to follow PEP8<commit_after>"""PageRank analysis of graph structure. """
#    Copyright (C) 2004-2011 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.
#    NetworkX:http://networkx.lanl.gov/
import networkx as nx
from networkx.exception import NetworkXError
__author__ = """Aric Hagberg (hagberg@lanl.gov)"""
__all__ = ['pagerank', 'pagerank_numpy', 'pagerank_scipy', 'google_matrix']

def pagerank(G, alpha=0.85, personalization=None,
             max_iter=100, tol=1.0e-8, nstart=None, weight='weight'):
    """Return the PageRank of the nodes in the graph.

    PageRank computes a ranking of the nodes in the graph G based on
    the structure of the incoming links. It was originally designed as
    an algorithm to rank web pages.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float, optional
      Damping parameter for PageRank, default=0.85

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    max_iter : integer, optional
      Maximum number of iterations in power method eigenvalue solver.

    tol : float, optional
      Error tolerance used to check convergence in power method solver.

    nstart : dictionary, optional
      Starting value of PageRank iteration for each node.

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    pagerank : dictionary
       Dictionary of nodes with PageRank as value

    Examples
    --------
    >>> G=nx.DiGraph(nx.path_graph(4))
    >>> pr=nx.pagerank(G,alpha=0.9)

    Notes
    -----
    The eigenvector calculation is done by the power iteration method
    and has no guarantee of convergence.  The iteration will stop
    after max_iter iterations or an error tolerance of
    number_of_nodes(G)*tol has been reached.

    The PageRank algorithm was designed for directed graphs but this
    algorithm does not check if the input graph is directed and will
    execute on undirected graphs by converting each oriented edge in the
    directed graph to two edges.

    See Also
    --------
    pagerank_numpy, pagerank_scipy, google_matrix

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry,
       The PageRank citation ranking: Bringing order to the Web. 1999
       http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf
    """
    if isinstance(G, nx.MultiGraph) or isinstance(G, nx.MultiDiGraph):
        raise Exception("pagerank() not defined for graphs with multiedges.")

    if len(G) == 0:
        return {}

    if not G.is_directed():
        D = G.to_directed()
    else:
        D = G

    # create a copy in (right) stochastic form
    W = nx.stochastic_graph(D, weight=weight)
    scale = 1.0 / W.number_of_nodes()

    # choose fixed starting vector if not given
    if nstart is None:
        x = dict.fromkeys(W, scale)
    else:
        x = nstart
        # normalize starting vector to 1
        s = 1.0 / sum(x.values())
        for k in x:
            x[k] *= s

    # assign uniform personalization/teleportation vector if not given
    if personalization is None:
        p = dict.fromkeys(W, scale)
    else:
        p = personalization
        # normalize starting vector to 1
        s = 1.0 / sum(p.values())
        for k in p:
            p[k] *= s
        if set(p) != set(G):
            raise NetworkXError('Personalization vector '
                                'must have a value for every node')

    # "dangling" nodes, no links out from them
    out_degree = W.out_degree()
    dangle = [n for n in W if out_degree[n] == 0.0]
    i = 0
    while True:  # power iteration: make up to max_iter iterations
        xlast = x
        x = dict.fromkeys(xlast.keys(), 0)
        danglesum = alpha * scale * sum(xlast[n] for n in dangle)
        for n in x:
            # this matrix multiply looks odd because it is
            # doing a left multiply x^T=xlast^T*W
            for nbr in W[n]:
                x[nbr] += alpha * xlast[n] * W[n][nbr][weight]
            x[n] += danglesum + (1.0 - alpha) * p[n]
        # normalize vector
        s = 1.0 / sum(x.values())
        for n in x:
            x[n] *= s
        # check convergence, l1 norm
        err = sum([abs(x[n] - xlast[n]) for n in x])
        if err < tol:
            break
        if i > max_iter:
            raise NetworkXError('pagerank: power iteration failed to converge '
                                'in %d iterations.' % (i - 1))
        i += 1
    return x

def google_matrix(G, alpha=0.85, personalization=None,
                  nodelist=None, weight='weight'):
    """Return the Google matrix of the graph.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float
      The damping factor

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    nodelist : list, optional
      The rows and columns are ordered according to the nodes in nodelist.
      If nodelist is None, then the ordering is produced by G.nodes().

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    A : NumPy matrix
       Google matrix of the graph

    See Also
    --------
    pagerank, pagerank_numpy, pagerank_scipy
    """
    try:
        import numpy as np
    except ImportError:
        raise ImportError(
            "google_matrix() requires NumPy: http://scipy.org/")
    # choose ordering in matrix
    if personalization is None:  # use G.nodes() ordering
        nodelist = G.nodes()
    else:  # use personalization "vector" ordering
        nodelist = personalization.keys()
        if set(nodelist) != set(G):
            raise NetworkXError('Personalization vector dictionary'
                                'must have a value for every node')
    M = nx.to_numpy_matrix(G, nodelist=nodelist, weight=weight)
    (n, m) = M.shape  # should be square
    if n == 0:
        return M
    # add constant to dangling nodes' row
    dangling = np.where(M.sum(axis=1) == 0)
    for d in dangling[0]:
        M[d] = 1.0 / n
    # normalize
    M = M / M.sum(axis=1)
    # add "teleportation"/personalization
    e = np.ones((n))
    if personalization is not None:
        v = np.array(list(personalization.values()), dtype=float)
    else:
        v = e
    v = v / v.sum()
    P = alpha * M + (1 - alpha) * np.outer(e, v)
    return P

def pagerank_numpy(G, alpha=0.85, personalization=None, weight='weight'):
    """Return the PageRank of the nodes in the graph.

    PageRank computes a ranking of the nodes in the graph G based on
    the structure of the incoming links. It was originally designed as
    an algorithm to rank web pages.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float, optional
      Damping parameter for PageRank, default=0.85

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    pagerank : dictionary
       Dictionary of nodes with PageRank as value

    Examples
    --------
    >>> G=nx.DiGraph(nx.path_graph(4))
    >>> pr=nx.pagerank_numpy(G,alpha=0.9)

    Notes
    -----
    The eigenvector calculation uses NumPy's interface to the LAPACK
    eigenvalue solvers.  This will be the fastest and most accurate
    for small graphs.

    This implementation works with Multi(Di)Graphs.

    See Also
    --------
    pagerank, pagerank_scipy, google_matrix

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry,
       The PageRank citation ranking: Bringing order to the Web. 1999
       http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf
    """
    try:
        import numpy as np
    except ImportError:
        raise ImportError("pagerank_numpy() requires NumPy: http://scipy.org/")
    if len(G) == 0:
        return {}
    # choose ordering in matrix
    if personalization is None:  # use G.nodes() ordering
        nodelist = G.nodes()
    else:  # use personalization "vector" ordering
        nodelist = personalization.keys()
    M = google_matrix(G, alpha, personalization=personalization,
                      nodelist=nodelist, weight=weight)
    # use numpy LAPACK solver
    eigenvalues, eigenvectors = np.linalg.eig(M.T)
    ind = eigenvalues.argsort()
    # eigenvector of largest eigenvalue at ind[-1], normalized
    largest = np.array(eigenvectors[:, ind[-1]]).flatten().real
    norm = float(largest.sum())
    centrality = dict(zip(nodelist, map(float, largest / norm)))
    return centrality

def pagerank_scipy(G, alpha=0.85, personalization=None,
                   max_iter=100, tol=1.0e-6, weight='weight'):
    """Return the PageRank of the nodes in the graph.

    PageRank computes a ranking of the nodes in the graph G based on
    the structure of the incoming links. It was originally designed as
    an algorithm to rank web pages.

    Parameters
    -----------
    G : graph
      A NetworkX graph

    alpha : float, optional
      Damping parameter for PageRank, default=0.85

    personalization: dict, optional
       The "personalization vector" consisting of a dictionary with a
       key for every graph node and nonzero personalization value for each node.

    max_iter : integer, optional
      Maximum number of iterations in power method eigenvalue solver.

    tol : float, optional
      Error tolerance used to check convergence in power method solver.

    weight : key, optional
      Edge data key to use as weight.  If None weights are set to 1.

    Returns
    -------
    pagerank : dictionary
       Dictionary of nodes with PageRank as value

    Examples
    --------
    >>> G=nx.DiGraph(nx.path_graph(4))
    >>> pr=nx.pagerank_scipy(G,alpha=0.9)

    Notes
    -----
    The eigenvector calculation uses power iteration with a SciPy
    sparse matrix representation.

    See Also
    --------
    pagerank, pagerank_numpy, google_matrix

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry,
       The PageRank citation ranking: Bringing order to the Web. 1999
       http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf
    """
    try:
        import scipy.sparse
    except ImportError:
        raise ImportError("pagerank_scipy() requires SciPy: http://scipy.org/")
    if len(G) == 0:
        return {}
    # choose ordering in matrix
    if personalization is None:  # use G.nodes() ordering
        nodelist = G.nodes()
    else:  # use personalization "vector" ordering
        nodelist = personalization.keys()
    M = nx.to_scipy_sparse_matrix(
        G, nodelist=nodelist, weight=weight, dtype='f')
    (n, m) = M.shape  # should be square
    S = scipy.array(M.sum(axis=1)).flatten()
#    for i, j, v in zip( *scipy.sparse.find(M) ):
#        M[i,j] = v / S[i]
    S[S > 0] = 1.0 / S[S > 0]
    Q = scipy.sparse.spdiags(S.T, 0, *M.shape, format='csr')
    M = Q * M
    x = scipy.ones((n)) / n  # initial guess
    dangle = scipy.array(scipy.where(M.sum(axis=1) == 0, 1.0 / n, 0)).flatten()
    # add "teleportation"/personalization
    if personalization is not None:
        v = scipy.array(list(personalization.values()), dtype=float)
        v = v / v.sum()
    else:
        v = x
    i = 0
    while i <= max_iter:
        # power iteration: make up to max_iter iterations
        xlast = x
        x = alpha * (x * M + scipy.dot(dangle, xlast)) + (1 - alpha) * v
        x = x / x.sum()
        # check convergence, l1 norm
        err = scipy.absolute(x - xlast).sum()
        if err < n * tol:
            return dict(zip(nodelist, map(float, x)))
        i += 1
    raise NetworkXError('pagerank_scipy: power iteration failed to converge'
                        'in %d iterations.' % (i + 1))

# fixture for nose tests
def setup_module(module):
    from nose import SkipTest
    try:
        import numpy
    except:
        raise SkipTest("NumPy not available")
    try:
        import scipy
    except:
        raise SkipTest("SciPy not available")
<|endoftext|>


<commit_before># Example for N Bit Binary Down Counter.

from __future__ import print_function
from BinPy.tools.digital import Clock
from BinPy.Sequential.counters import NBitDownCounter
from BinPy.Gates import Connector
from BinPy.tools.oscilloscope import Oscilloscope

print("Initialize a toggle connectr for inpput in TFlipFlop")
print("toggle = Connector(1)")
toggle = Connector(1)

print("Initializing the Clock")
print("clock = Clock(1, 50)")
print("clock.start()")
clock = Clock(1, 50)
clock.start()
# A clock of 100 hertz frequency
print("clk_conn = clock.A")
clk_conn = clock.A
print("\n")

print("Initialize enable")
print("enable = Connector(1)")
enable = Connector(1)

print ("Setting No of Bits to 4")
print ("Clock frequency is 10 Hz")

# Initializing the counter
print("\n")
print("Initializing Down Counter with 4 bits and clock_conn")
print("b = NBitDownCounter(4, clk_conn)")
b = NBitDownCounter(4, clk_conn)

# Initiating the oscilloscope
print("\n")
print("Initializing the Oscillioscope")
print(
    "o = Oscilloscope((clk_conn, 'CLK'), (b.out[0], 'BIT3'), (b.out[1], 'BIT2'), (\
    b.out[2], 'BIT1'), (b.out[3], 'BIT0'), (enable, 'EN1'))")
print("o.start() # starting the oscillioscope")
print("o.setScale(0.05) # setting the scale")
o = Oscilloscope((clk_conn, 'CLK'), (b.out[0], 'BIT3'), (b.out[1], 'BIT2'), (
    b.out[2], 'BIT1'), (b.out[3], 'BIT0'), (enable, 'EN1'))
o.start()
o.setScale(0.0005)  # Set scale by trial and error.
o.unhold()

print ("Initial State")
print (b.state())

print ("Triggering the counter sequentially 2^4 + 1 times")

for i in range(1, 2 ** 4 + 2):
    b.trigger()
    print (b.state())

o.display()
o.kill()
clock.kill()

print("\n")
print("Calling the instance will trigger")
print("b()")
b()
print("b.state()")
print(b.state())

print("\n")
print("Setting the Counter")
print("b.setCounter()")
b.setCounter()
print("b.state()")
print(b.state())

print("\n")
print("Resetting the Counter")
print("b.resetCounter()")
b.resetCounter()
print("b.state()")
print(b.state())

print("\n")
print("Disabling the Counter")
print("b.disable()\nb.trigger()")
b.disable()
b.trigger()
print("b.state()")
print(b.state())

print("\n")
print("Enabling the Counter")
print("b.enable()\nb.trigger()")
b.enable()
b.trigger()
print("b.state()")
print(b.state())
<commit_msg>Modified the example for NBitDownCounter<commit_after># Example for N Bit Binary Down Counter.

from __future__ import print_function
from BinPy.tools.digital import Clock
from BinPy.Sequential.counters import NBitDownCounter
from BinPy.Gates import Connector
from BinPy.tools.oscilloscope import Oscilloscope

# Initialize the clock
clock = Clock(1, 20)
clock.start()
# A clock of 20 hertz frequency
clk_conn = clock.A

enable = Connector(1)

print ("Setting No of Bits to 4")
print ("Clock frequency is 20 Hz")

# Initializing the counter
b = NBitDownCounter(4, clk_conn)

# Initiating the oscilloscope
o = Oscilloscope((clk_conn, 'CLK'), (b.out[0], 'BIT3'), (b.out[1], 'BIT2'), (
    b.out[2], 'BIT1'), (b.out[3], 'BIT0'), (enable, 'EN1'))
o.start()
o.setScale(0.01)  # Set scale by trial and error.
o.unhold()

print ("INITIAL STATE")
print (b.state())

print ("TRIGGERING THE COUNTER SEQUENTIALLY 2^4 + 1 times")

for i in range(1, 2 ** 4 + 2):
    b.trigger()
    print (b.state())

o.display()
o.kill()
clock.kill()<|endoftext|>


<commit_before>import re
import os
import json
import logging
import requests
import dataset
# from pprint import pprint
from normality import slugify
from datetime import datetime
from unicodecsv import DictWriter
from itertools import count
from morphium import Archive, env

log = logging.getLogger('flexicadastre')
db_uri = env('DATABASE_URI', 'sqlite:///data.sqlite')
archive = Archive(bucket='archive.pudo.org', prefix='flexicadastre')
data_path = env('DATA_PATH', 'data')
database = dataset.connect(db_uri)
index_table = database['data']

# comment out countries here to disable scraping the
# respective countries.
SITES = {
    # 'BW': 'http://portals.flexicadastre.com/botswana/',
    'UG': 'http://portals.flexicadastre.com/uganda/',
    'NA': 'http://portals.flexicadastre.com/Namibia/',
    'MZ': 'http://portals.flexicadastre.com/mozambique/en/',
    'LR': 'http://portals.flexicadastre.com/liberia/',
    'KE': 'https://portal.miningcadastre.go.ke/mapportal/',
    'RW': 'http://portals.flexicadastre.com/rwanda/',
    'TZ': 'http://portal.mem.go.tz/map/',
    'ZM': 'http://portals.flexicadastre.com/zambia/',
    'CD': 'http://portals.flexicadastre.com/drc/en/',
    'SS': 'http://portals.flexicadastre.com/southsudan/',
    'PG': 'http://portal.mra.gov.pg/Map/'
}

IGNORE = ['rw_25ha_grid', 'mz_moz_geol', 'ug_north']

# there's been some trouble in the past with regards to the
# greographic reference system used. the settings here
# should emit the closest that ESRI will give you in lieu of
# WGS84 (i.e. Google Maps).
QUERY = {
    'where': '1=1',
    'outFields': '*',
    'geometryType': 'esriGeometryPolygon',
    'spatialRel': 'esriSpatialRelIntersects',
    # 'units': 'esriSRUnit_Meter',
    'outSR': 102100,  # wgs 84
    'resultRecordCount': 500,
    'resultOffset': 0,
    'returnGeometry': 'true',
    'f': 'pjson'
}

def convrow(data):
    # this converts all values in the attribute data to a
    # form suitable for the database storage.
    row = {}
    for name, val in data.items():
        name = name.upper()
        if val is not None and isinstance(val, int):
            if name.startswith('DTE') or name.endswith('_DAT') \
                    or name.endswith('_DATE') or name.endswith('_D') \
                    or name == 'COMPLETED':
                dt = datetime.fromtimestamp(int(val) / 1000)
                val = dt.date().isoformat()
        if name.startswith('GUID'):
            continue
        if name == 'AREA':
            val = min(val, (2 ** 31) - 1)
        if name == 'ID':
            name = 'FC_ID'
        if not len(unicode(val).strip()):
            val = None
        row[slugify(name, sep='_')] = val
    return row

def store_layer_to_csv(res_name, data, layer, features):
    """Load a layer of features into a database table."""
    # table names are generated from the name of the layer and
    # the name of the country.
    csv_path = os.path.join(data_path, '%s.csv' % res_name)
    log.info('CSV: %s: %s rows', csv_path, len(features))

    with open(csv_path, 'w') as fh:
        writer = None
        for feature in features:
            row = convrow(feature['attributes'])
            row['layer_name'] = layer['name']
            row['layer_id'] = layer['id']
            row['source_name'] = data['name']
            row['source_title'] = data['title']
            row['source_url'] = data['url']

            # store the geometry as JSON. not sure this is a
            # great idea because it may make the resulting
            # CSV files really hard to parse.
            # row['_geometry'] = json.dumps(feature['geometry'])

            if writer is None:
                writer = DictWriter(fh, row.keys())
                writer.writeheader()

            writer.writerow(row)

    url = archive.upload_file(csv_path)
    os.unlink(csv_path)
    return url

def store_layer_to_geojson(res_name, data, layer, features):
    """Store the returned data as a GeoJSON file."""
    # skip if we're not loading geometries:
    if QUERY['returnGeometry'] != 'true':
        return

    out = {
        "type": "FeatureCollection",
        "features": []
    }
    for fdata in features:
        attrs = {}
        for k, v in fdata.get('attributes').items():
            k = k.lower().strip()
            attrs[k] = v

        if not fdata.get('geometry', {}).get('rings'):
            continue

        props = dict(attrs)
        props['layer'] = layer.get('name')
        out['features'].append({
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates': fdata.get('geometry', {}).get('rings')
            },
            'properties': props
        })

    file_path = os.path.join(data_path, '%s.geo.json' % res_name)
    log.info('GeoJSON: %s', file_path)
    with open(file_path, 'wb') as fh:
        json.dump(out, fh)

    url = archive.upload_file(file_path)
    os.unlink(file_path)
    return url

def scrape_layers(sess, data, token, rest_url):
    # This is the actual scraping of the ESRI API.
    res = sess.get(rest_url, params={'f': 'json', 'token': token})
    log.info('Scraping %(title)r', data)
    for layer in res.json().get('layers'):
        res_name = '%s %s' % (data['name'], layer['name'])
        res_name = slugify(res_name, sep='_')
        log.info('Layer: [%s] %s (%s) ', layer['id'], layer['name'], res_name)

        if res_name in IGNORE:
            log.info("[%(name)s] Skip (blacklisted)", layer)
            continue

        query_url = '%s/%s/query' % (rest_url, layer['id'])
        q = QUERY.copy()
        q['token'] = token
        features = []
        for i in count(0):
            q['resultOffset'] = q['resultRecordCount'] * i
            res = sess.get(query_url, params=q)
            page = res.json()
            features.extend(page.get('features', []))
            if not page.get('exceededTransferLimit'):
                break

        csv_url = store_layer_to_csv(res_name, data, layer, features)
        json_url = store_layer_to_geojson(res_name, data, layer, features)
        index_table.upsert({
            'resource': res_name,
            'tag': archive.tag,
            'csv_url': csv_url,
            'json_url': json_url,
            'features': len(features),
            'layer_name': layer['name'],
            'layer_id': layer['id'],
            'source_name': data['name'],
            'source_title': data['title'],
            'source_url': data['url']
        }, ['resource'])

def scrape_configs():
    for name, url in SITES.items():
        sess = requests.Session()
        res = sess.get(url)
        # some ugly stuff to extraxt the access token from the portal
        # site.
        groups = re.search(r"MainPage\.Init\('(.*)'", res.content)
        text = groups.group(1)
        text = text.replace("\\\\\\'", "")
        text = text.replace("\\'", "")
        text = text.replace('\\\\\\"', "")

        text = '"%s"' % text
        cfg = json.loads(json.loads(text))
        token = cfg['Extras'].pop()
        data = {
            'name': name,
            'title': cfg['Title'],
            'url': url
        }
        try:
            for service in cfg['MapServices']:
                if service['MapServiceType'] == 'Features':
                    rest_url = service['RestUrl']
                    scrape_layers(sess, data, token, rest_url)
        except Exception, e:
            log.exception(e)

if __name__ == '__main__':
    try:
        os.makedirs(data_path)
    except Exception:
        pass
    scrape_configs()
<commit_msg>disable geometry for now<commit_after>import re
import os
import json
import logging
import requests
import dataset
# from pprint import pprint
from normality import slugify
from datetime import datetime
from unicodecsv import DictWriter
from itertools import count
from morphium import Archive, env

log = logging.getLogger('flexicadastre')
db_uri = env('DATABASE_URI', 'sqlite:///data.sqlite')
archive = Archive(bucket='archive.pudo.org', prefix='flexicadastre')
data_path = env('DATA_PATH', 'data')
database = dataset.connect(db_uri)
index_table = database['data']

# comment out countries here to disable scraping the
# respective countries.
SITES = {
    # 'BW': 'http://portals.flexicadastre.com/botswana/',
    'UG': 'http://portals.flexicadastre.com/uganda/',
    'NA': 'http://portals.flexicadastre.com/Namibia/',
    'MZ': 'http://portals.flexicadastre.com/mozambique/en/',
    'LR': 'http://portals.flexicadastre.com/liberia/',
    'KE': 'https://portal.miningcadastre.go.ke/mapportal/',
    'RW': 'http://portals.flexicadastre.com/rwanda/',
    'TZ': 'http://portal.mem.go.tz/map/',
    'ZM': 'http://portals.flexicadastre.com/zambia/',
    'CD': 'http://portals.flexicadastre.com/drc/en/',
    'SS': 'http://portals.flexicadastre.com/southsudan/',
    'PG': 'http://portal.mra.gov.pg/Map/'
}

# IGNORE = ['rw_25ha_grid', 'mz_moz_geol', 'ug_north']
IGNORE = []

# there's been some trouble in the past with regards to the
# greographic reference system used. the settings here
# should emit the closest that ESRI will give you in lieu of
# WGS84 (i.e. Google Maps).
QUERY = {
    'where': '1=1',
    'outFields': '*',
    'geometryType': 'esriGeometryPolygon',
    'spatialRel': 'esriSpatialRelIntersects',
    # 'units': 'esriSRUnit_Meter',
    'outSR': 102100,  # wgs 84
    'resultRecordCount': 500,
    'resultOffset': 0,
    # 'returnGeometry': 'true',
    'returnGeometry': 'false',
    'f': 'pjson'
}

def convrow(data):
    # this converts all values in the attribute data to a
    # form suitable for the database storage.
    row = {}
    for name, val in data.items():
        name = name.upper()
        if val is not None and isinstance(val, int):
            if name.startswith('DTE') or name.endswith('_DAT') \
                    or name.endswith('_DATE') or name.endswith('_D') \
                    or name == 'COMPLETED':
                dt = datetime.fromtimestamp(int(val) / 1000)
                val = dt.date().isoformat()
        if name.startswith('GUID'):
            continue
        if name == 'AREA':
            val = min(val, (2 ** 31) - 1)
        if name == 'ID':
            name = 'FC_ID'
        if not len(unicode(val).strip()):
            val = None
        row[slugify(name, sep='_')] = val
    return row

def store_layer_to_csv(res_name, data, layer, features):
    """Load a layer of features into a database table."""
    # table names are generated from the name of the layer and
    # the name of the country.
    csv_path = os.path.join(data_path, '%s.csv' % res_name)
    log.info('CSV: %s: %s rows', csv_path, len(features))

    with open(csv_path, 'w') as fh:
        writer = None
        for feature in features:
            row = convrow(feature['attributes'])
            row['layer_name'] = layer['name']
            row['layer_id'] = layer['id']
            row['source_name'] = data['name']
            row['source_title'] = data['title']
            row['source_url'] = data['url']

            # store the geometry as JSON. not sure this is a
            # great idea because it may make the resulting
            # CSV files really hard to parse.
            # row['_geometry'] = json.dumps(feature['geometry'])

            if writer is None:
                writer = DictWriter(fh, row.keys())
                writer.writeheader()

            writer.writerow(row)

    url = archive.upload_file(csv_path)
    os.unlink(csv_path)
    return url

def store_layer_to_geojson(res_name, data, layer, features):
    """Store the returned data as a GeoJSON file."""
    # skip if we're not loading geometries:
    if QUERY['returnGeometry'] != 'true':
        return

    out = {
        "type": "FeatureCollection",
        "features": []
    }
    for fdata in features:
        attrs = {}
        for k, v in fdata.get('attributes').items():
            k = k.lower().strip()
            attrs[k] = v

        if not fdata.get('geometry', {}).get('rings'):
            continue

        props = dict(attrs)
        props['layer'] = layer.get('name')
        out['features'].append({
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates': fdata.get('geometry', {}).get('rings')
            },
            'properties': props
        })

    file_path = os.path.join(data_path, '%s.geo.json' % res_name)
    log.info('GeoJSON: %s', file_path)
    with open(file_path, 'wb') as fh:
        json.dump(out, fh)

    url = archive.upload_file(file_path)
    os.unlink(file_path)
    return url

def scrape_layers(sess, data, token, rest_url):
    # This is the actual scraping of the ESRI API.
    res = sess.get(rest_url, params={'f': 'json', 'token': token})
    log.info('Scraping %(title)r', data)
    for layer in res.json().get('layers'):
        res_name = '%s %s' % (data['name'], layer['name'])
        res_name = slugify(res_name, sep='_')
        log.info('Layer: [%s] %s (%s) ', layer['id'], layer['name'], res_name)

        if res_name in IGNORE:
            log.info("[%(name)s] Skip (blacklisted)", layer)
            continue

        query_url = '%s/%s/query' % (rest_url, layer['id'])
        q = QUERY.copy()
        q['token'] = token
        features = []
        for i in count(0):
            q['resultOffset'] = q['resultRecordCount'] * i
            res = sess.get(query_url, params=q)
            page = res.json()
            features.extend(page.get('features', []))
            if not page.get('exceededTransferLimit'):
                break

        csv_url = store_layer_to_csv(res_name, data, layer, features)
        # json_url = store_layer_to_geojson(res_name, data, layer, features)

        index_table.upsert({
            'resource': res_name,
            'tag': archive.tag,
            'csv_url': csv_url,
            # 'json_url': json_url,
            'features': len(features),
            'layer_name': layer['name'],
            'layer_id': layer['id'],
            'source_name': data['name'],
            'source_title': data['title'],
            'source_url': data['url']
        }, ['resource'])

def scrape_configs():
    for name, url in SITES.items():
        sess = requests.Session()
        res = sess.get(url)
        # some ugly stuff to extraxt the access token from the portal
        # site.
        groups = re.search(r"MainPage\.Init\('(.*)'", res.content)
        text = groups.group(1)
        text = text.replace("\\\\\\'", "")
        text = text.replace("\\'", "")
        text = text.replace('\\\\\\"', "")

        text = '"%s"' % text
        cfg = json.loads(json.loads(text))
        token = cfg['Extras'].pop()
        data = {
            'name': name,
            'title': cfg['Title'],
            'url': url
        }
        try:
            for service in cfg['MapServices']:
                if service['MapServiceType'] == 'Features':
                    rest_url = service['RestUrl']
                    scrape_layers(sess, data, token, rest_url)
        except Exception, e:
            log.exception(e)

if __name__ == '__main__':
    try:
        os.makedirs(data_path)
    except Exception:
        pass
    scrape_configs()
<|endoftext|>


<commit_before>from __future__ import absolute_import, division, print_function, unicode_literals
import os
import zipfile
from PySide.QtCore import Qt

from arrow import arrow
from PySide import QtGui, QtCore
from mcedit2.appsettings import RecentFilesSetting
from mcedit2.rendering import blockmeshes
from mcedit2.rendering.blockmodels import BlockModels
from mcedit2.rendering.chunkloader import ChunkLoader
from mcedit2.rendering.textureatlas import TextureAtlas
from mcedit2.util import profiler, minecraftinstall
from mcedit2.util.load_ui import load_ui
from mcedit2.util.minecraftinstall import MinecraftInstallsDialog
from mcedit2.util.screen import centerWidgetInScreen
from mcedit2.util.worldloader import LoaderTimer

from mcedit2.widgets.layout import Column, Row, setWidgetError
from mcedit2.worldview.minimap import MinimapWorldView
from mceditlib.anvil.adapter import AnvilWorldAdapter
from mceditlib.geometry import Vector
from mceditlib.exceptions import LevelFormatError, PlayerNotFound
from mceditlib import worldeditor

import logging
from mceditlib.findadapter import isLevel, findAdapter
from mceditlib.util import displayName

log = logging.getLogger(__name__)

def lastPlayedTime(adapter):
    try:
        time = adapter.metadata.LastPlayed
        dt = arrow.Arrow.fromtimestamp(time / 1000.0)
        return dt
    except AttributeError as e:
        return None

def usefulFilename(adapter):
    if hasattr(adapter, 'worldFolder'):
        return os.path.basename(adapter.worldFolder.filename)
    else:
        return os.path.basename(adapter.filename)

class WorldListItemWidget(QtGui.QWidget):
    doubleClicked = QtCore.Signal()

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.displayNameLabel = QtGui.QLabel("namenamename")
        self.lastPlayedLabel = QtGui.QLabel("lastplayed")

        #self.sizeLabel = QtGui.QLabel(self.tr("Calculating area..."))
        # areaText = self.tr("%.02f million square meters") % (world.chunkCount * 0.25)
        # diskSize = 0
        # if hasattr(worldAdapter, 'worldFolder'):
        #     folder = worldAdapter.worldFolder
        #     for rf in folder.findRegionFiles():
        #         diskSize += os.stat(rf).st_size
        # else:
        #     diskSize = os.stat(worldAdapter.filename).st_size
        #
        # self.diskSizeLabel = QtGui.QLabel(self.tr("%0.2f MB") % (diskSize / 1000000.0))

        infoColumn = Column(
            self.displayNameLabel,
            self.lastPlayedLabel,
            #self.diskSizeLabel,
            None
        )

        layout = Row(20, infoColumn)

        self.setLayout(layout)

    def setWorldInfo(self, (name, lastPlayedText)):
        self.displayNameLabel.setText(name)
        self.lastPlayedLabel.setText(lastPlayedText)

    def mouseDoubleClickEvent(self, event):
        self.doubleClicked.emit()

    def setErrorMessage(self, msg):
        self.sizeLabel.setText(msg)

def getWorldInfo(filename):
    worldAdapter = findAdapter(filename, readonly=True)
    try:
        displayNameLimit = 40
        name = displayName(worldAdapter.filename)

        if len(name) > displayNameLimit:
            name = name[:displayNameLimit] + "..."
        if usefulFilename(worldAdapter) != displayName(worldAdapter.filename):
            name = "%s (%s)" % (name, usefulFilename(worldAdapter))

        lastPlayed = lastPlayedTime(worldAdapter)
        lastPlayedText = lastPlayed.humanize() if lastPlayed else "Unknown"
        return name, lastPlayedText
    except EnvironmentError as e:
        log.error("Failed getting world info for %s: %s", filename, e)
        return str(e), ""

class WorldListItemDelegate(QtGui.QStyledItemDelegate):
    def __init__(self):
        super(WorldListItemDelegate, self).__init__()
        self.itemWidget = WorldListItemWidget()
        self.itemWidget.adjustSize()
        log.info("Size hint: %s", str(self.itemWidget.sizeHint()))
        log.info("Size : %s", str(self.itemWidget.size()))

    def paint(self, painter, option, index):
        """

        :param painter:
        :type painter: QtGui.QPainter
        :param option:
        :type option: QtGui.QStyleOptionViewItemV4
        :param index:
        :type index:
        :return:
        :rtype:
        """
        option = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(option, index)
        style = QtGui.qApp.style()
        worldInfo = index.data(Qt.UserRole)
        style.drawPrimitive(QtGui.QStyle.PE_PanelItemViewItem, option, painter, self.parent())
        self.itemWidget.setGeometry(option.rect)
        self.itemWidget.setWorldInfo(worldInfo)
        self.itemWidget.render(painter,
                               painter.deviceTransform().map(option.rect.topLeft()),  # QTBUG-26694
                               renderFlags=QtGui.QWidget.DrawChildren)

    def sizeHint(self, option, index):
        return self.itemWidget.sizeHint()

class WorldListModel(QtCore.QAbstractListModel):
    def __init__(self, worlds=None):
        super(WorldListModel, self).__init__()
        if worlds is None:
            worlds = []

        self.worlds = [(f, getWorldInfo(f)) for f in worlds]

    def rowCount(self, index):
        if index.isValid():
            return 0

        return len(self.worlds)

    def data(self, index, role=Qt.DisplayRole):
        if index.column() != 0:
            return
        row = index.row()

        if role == Qt.DisplayRole:
            return self.worlds[row][0]
        if role == Qt.UserRole:
            return self.worlds[row][1]

    def flags(self, index):
        if not index.isValid():
            return 0
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable

class WorldListWidget(QtGui.QDialog):
    def __init__(self, parent=None, f=0):
        super(WorldListWidget, self).__init__(parent, f)
        self.setWindowTitle("World List")
        load_ui('world_list.ui', baseinstance=self)

        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = None
        self.blankWidget = QtGui.QWidget()
        self.stackedWidget.addWidget(self.blankWidget)

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)
        self.viewButton.setEnabled(False)

        self.openWorldButton.clicked.connect(self.openWorldClicked)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        centerWidgetInScreen(self, 0.75)

        delegate = WorldListItemDelegate()
        self.worldListView.setItemDelegate(delegate)
        delegate.setParent(self.worldListView)  # PYSIDE-152: get the view widget to the drawPrimitive call

        self.worldListView.clicked.connect(self.worldListItemClicked)
        self.worldListView.doubleClicked.connect(self.worldListItemDoubleClicked)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        self._updateInstalls()

        self.savesFolderComboBox.currentIndexChanged.connect(self.reloadList)

        self.worldListModel = None
        self.reloadList()
        self.reloadRecentWorlds()

    def _updateInstalls(self):
        for install in minecraftinstall.GetInstalls().installs:
            self.minecraftInstallBox.addItem(install.name)

        self.minecraftInstallBox.setCurrentIndex(minecraftinstall.GetInstalls().selectedInstallIndex())

        self._updateVersionsAndResourcePacks()

    def _updateVersionsAndResourcePacks(self):
        install = minecraftinstall.GetInstalls().getInstall(self.minecraftInstallBox.currentIndex())

        self.minecraftVersionBox.clear()
        for version in sorted(install.versions, reverse=True):
            self.minecraftVersionBox.addItem(version)

        self.resourcePackBox.clear()
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))
        for resourcePack in sorted(install.resourcePacks):
            self.resourcePackBox.addItem(resourcePack)

        self.saveDirs = install.getSaveDirs()
        self.savesFolderComboBox.clear()
        for filename in self.saveDirs:
            self.savesFolderComboBox.addItem(os.path.basename(os.path.dirname(filename)), (filename, None))
        for index, instance in enumerate(minecraftinstall.GetInstalls().instances):  # xxx instanceID?
            self.savesFolderComboBox.addItem(instance.name, (instance.saveFileDir, index))

    def getSelectedIVP(self):
        i = self.minecraftInstallBox.currentIndex()
        install = minecraftinstall.GetInstalls().getInstall(i)
        v = self.minecraftVersionBox.currentText()
        if self.resourcePackBox.currentIndex() > 0:
            p = self.resourcePackBox.currentText()
        else:
            p = None
        return install, v, p

    def reloadRecentWorlds(self):
        recentWorlds = RecentFilesSetting.value()
        self.recentWorldsMenu = QtGui.QMenu()

        def _triggered(f):
            def triggered():
                self.accept()
                self.editWorldClicked.emit(f)
            return triggered

        for filename in recentWorlds:
            try:
                displayName, lastPlayed = getWorldInfo(filename)
                action = self.recentWorldsMenu.addAction(displayName)
                action._editWorld = _triggered(filename)
                action.triggered.connect(action._editWorld)
            except EnvironmentError as e:
                log.exception("Failed to load world info")

        self.recentWorldsButton.setMenu(self.recentWorldsMenu)

    def reloadList(self):
        try:
            itemData = self.savesFolderComboBox.itemData(self.savesFolderComboBox.currentIndex())
            if itemData is None:
                log.error("No item selected in savesFolderComboBox!!(?)")
                return
            saveFileDir, instanceIndex = itemData
            if instanceIndex is not None:
                # disable version selector, update resource packs(?)
                pass
            if not os.path.isdir(saveFileDir):
                raise IOError(u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)".format(saveFileDir))

            log.info("Scanning %s for worlds...", saveFileDir)
            potentialWorlds = os.listdir(saveFileDir)
            potentialWorlds = [os.path.join(saveFileDir, p) for p in potentialWorlds]
            worldFiles = [p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)]

            self.worldListModel = WorldListModel(worldFiles)
            self.worldListView.setModel(self.worldListModel)

            if len(self.worldListModel.worlds):
                self.worldListView.setFocus()
                self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
                self.showWorld(self.worldListModel.worlds[0][0])

        except EnvironmentError as e:
            setWidgetError(self, e)

    def openWorldClicked(self):
        QtGui.qApp.chooseOpenWorld()

    _currentFilename = None

    def worldListItemClicked(self, index):
        filename = index.data()
        if filename != self._currentFilename:
            self._currentFilename = filename
            self.showWorld(filename)

    def worldListItemDoubleClicked(self, index):
        row = index.row()
        self.accept()
        self.editWorldClicked.emit(self.worldListModel.worlds[row][0])

    def showWorld(self, filename):
        self.removeWorldView()

        try:
            worldEditor = worldeditor.WorldEditor(filename, readonly=True)
            i, v, p = self.getSelectedIVP()
            resLoader = i.getResourceLoader(v, p)
            blockModels = BlockModels(worldEditor.blocktypes, resLoader)
            textureAtlas = TextureAtlas(worldEditor, resLoader, blockModels)

        except (EnvironmentError, LevelFormatError, zipfile.BadZipfile) as e:
            self.errorWidget = QtGui.QWidget()
            setWidgetError(self.errorWidget, e)
            self.stackedWidget.addWidget(self.errorWidget)
            self.stackedWidget.setCurrentWidget(self.errorWidget)

        else:

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim, textureAtlas))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                player = worldEditor.getPlayer()
                log.info("Centering on single-player player.")
            except PlayerNotFound:
                try:
                    center = worldEditor.worldSpawnPosition()
                    log.info("Centering on spawn position.")
                except AttributeError:
                    log.info("Centering on world center")
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)
            else:
                if player.dimName == dim.dimName:
                    center = Vector(*player.Position)
                    self.worldView.centerOnPoint(center)
                else:
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)

            self.worldView.centerOnPoint(center)
            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)
        self.stackedWidget.setCurrentWidget(worldView)

    def removeWorldView(self):
        self.stackedWidget.setCurrentWidget(self.blankWidget)
        QtGui.qApp.processEvents()  # force repaint of stackedWidget to hide old error widget
        if self.worldView:
            log.info("Removing view from WorldListWidget")
            self.worldView.textureAtlas.dispose()
            self.worldView.destroy()
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView.setParent(None)
            self.worldView = None
        if self.errorWidget:
            self.stackedWidget.removeWidget(self.errorWidget)
            self.errorWidget = None

        self.chunkLoader = None

    def hide(self):
        self.removeWorldView()
        super(WorldListWidget, self).hide()

    def close(self):
        self.removeWorldView()
        super(WorldListWidget, self).close()

    def reject(self):
        self.removeWorldView()
        super(WorldListWidget, self).reject()

    def showEvent(self, event):
        if self.worldListModel and len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])

        self.reloadRecentWorlds()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    @property
    def selectedWorldIndex(self):
        indexes = self.worldListView.selectedIndexes()
        if len(indexes):
            return indexes[0]

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.editWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def viewClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.viewWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def repairClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.repairWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def backupClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.backupWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateVersionsAndResourcePacks()
<commit_msg>Catch ValueError when getting string form of LastPlayed time, to catch times before 1970<commit_after>from __future__ import absolute_import, division, print_function, unicode_literals
import os
import zipfile
from PySide.QtCore import Qt

from arrow import arrow
from PySide import QtGui, QtCore
from mcedit2.appsettings import RecentFilesSetting
from mcedit2.rendering import blockmeshes
from mcedit2.rendering.blockmodels import BlockModels
from mcedit2.rendering.chunkloader import ChunkLoader
from mcedit2.rendering.textureatlas import TextureAtlas
from mcedit2.util import profiler, minecraftinstall
from mcedit2.util.load_ui import load_ui
from mcedit2.util.minecraftinstall import MinecraftInstallsDialog
from mcedit2.util.screen import centerWidgetInScreen
from mcedit2.util.worldloader import LoaderTimer

from mcedit2.widgets.layout import Column, Row, setWidgetError
from mcedit2.worldview.minimap import MinimapWorldView
from mceditlib.anvil.adapter import AnvilWorldAdapter
from mceditlib.geometry import Vector
from mceditlib.exceptions import LevelFormatError, PlayerNotFound
from mceditlib import worldeditor

import logging
from mceditlib.findadapter import isLevel, findAdapter
from mceditlib.util import displayName

log = logging.getLogger(__name__)

def lastPlayedTime(adapter):
    try:
        time = adapter.metadata.LastPlayed
        dt = arrow.Arrow.fromtimestamp(time / 1000.0)
        return dt
    except (AttributeError, ValueError) as e:  # no lastplayed, or time is before 1970
        return None

def usefulFilename(adapter):
    if hasattr(adapter, 'worldFolder'):
        return os.path.basename(adapter.worldFolder.filename)
    else:
        return os.path.basename(adapter.filename)

class WorldListItemWidget(QtGui.QWidget):
    doubleClicked = QtCore.Signal()

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.displayNameLabel = QtGui.QLabel("namenamename")
        self.lastPlayedLabel = QtGui.QLabel("lastplayed")

        #self.sizeLabel = QtGui.QLabel(self.tr("Calculating area..."))
        # areaText = self.tr("%.02f million square meters") % (world.chunkCount * 0.25)
        # diskSize = 0
        # if hasattr(worldAdapter, 'worldFolder'):
        #     folder = worldAdapter.worldFolder
        #     for rf in folder.findRegionFiles():
        #         diskSize += os.stat(rf).st_size
        # else:
        #     diskSize = os.stat(worldAdapter.filename).st_size
        #
        # self.diskSizeLabel = QtGui.QLabel(self.tr("%0.2f MB") % (diskSize / 1000000.0))

        infoColumn = Column(
            self.displayNameLabel,
            self.lastPlayedLabel,
            #self.diskSizeLabel,
            None
        )

        layout = Row(20, infoColumn)

        self.setLayout(layout)

    def setWorldInfo(self, (name, lastPlayedText)):
        self.displayNameLabel.setText(name)
        self.lastPlayedLabel.setText(lastPlayedText)

    def mouseDoubleClickEvent(self, event):
        self.doubleClicked.emit()

    def setErrorMessage(self, msg):
        self.sizeLabel.setText(msg)

def getWorldInfo(filename):
    worldAdapter = findAdapter(filename, readonly=True)
    try:
        displayNameLimit = 40
        name = displayName(worldAdapter.filename)

        if len(name) > displayNameLimit:
            name = name[:displayNameLimit] + "..."
        if usefulFilename(worldAdapter) != displayName(worldAdapter.filename):
            name = "%s (%s)" % (name, usefulFilename(worldAdapter))

        lastPlayed = lastPlayedTime(worldAdapter)
        lastPlayedText = lastPlayed.humanize() if lastPlayed else "Unknown"
        return name, lastPlayedText
    except EnvironmentError as e:
        log.error("Failed getting world info for %s: %s", filename, e)
        return str(e), ""

class WorldListItemDelegate(QtGui.QStyledItemDelegate):
    def __init__(self):
        super(WorldListItemDelegate, self).__init__()
        self.itemWidget = WorldListItemWidget()
        self.itemWidget.adjustSize()
        log.info("Size hint: %s", str(self.itemWidget.sizeHint()))
        log.info("Size : %s", str(self.itemWidget.size()))

    def paint(self, painter, option, index):
        """

        :param painter:
        :type painter: QtGui.QPainter
        :param option:
        :type option: QtGui.QStyleOptionViewItemV4
        :param index:
        :type index:
        :return:
        :rtype:
        """
        option = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(option, index)
        style = QtGui.qApp.style()
        worldInfo = index.data(Qt.UserRole)
        style.drawPrimitive(QtGui.QStyle.PE_PanelItemViewItem, option, painter, self.parent())
        self.itemWidget.setGeometry(option.rect)
        self.itemWidget.setWorldInfo(worldInfo)
        self.itemWidget.render(painter,
                               painter.deviceTransform().map(option.rect.topLeft()),  # QTBUG-26694
                               renderFlags=QtGui.QWidget.DrawChildren)

    def sizeHint(self, option, index):
        return self.itemWidget.sizeHint()

class WorldListModel(QtCore.QAbstractListModel):
    def __init__(self, worlds=None):
        super(WorldListModel, self).__init__()
        if worlds is None:
            worlds = []

        self.worlds = [(f, getWorldInfo(f)) for f in worlds]

    def rowCount(self, index):
        if index.isValid():
            return 0

        return len(self.worlds)

    def data(self, index, role=Qt.DisplayRole):
        if index.column() != 0:
            return
        row = index.row()

        if role == Qt.DisplayRole:
            return self.worlds[row][0]
        if role == Qt.UserRole:
            return self.worlds[row][1]

    def flags(self, index):
        if not index.isValid():
            return 0
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable

class WorldListWidget(QtGui.QDialog):
    def __init__(self, parent=None, f=0):
        super(WorldListWidget, self).__init__(parent, f)
        self.setWindowTitle("World List")
        load_ui('world_list.ui', baseinstance=self)

        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = None
        self.blankWidget = QtGui.QWidget()
        self.stackedWidget.addWidget(self.blankWidget)

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)
        self.viewButton.setEnabled(False)

        self.openWorldButton.clicked.connect(self.openWorldClicked)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        centerWidgetInScreen(self, 0.75)

        delegate = WorldListItemDelegate()
        self.worldListView.setItemDelegate(delegate)
        delegate.setParent(self.worldListView)  # PYSIDE-152: get the view widget to the drawPrimitive call

        self.worldListView.clicked.connect(self.worldListItemClicked)
        self.worldListView.doubleClicked.connect(self.worldListItemDoubleClicked)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        self._updateInstalls()

        self.savesFolderComboBox.currentIndexChanged.connect(self.reloadList)

        self.worldListModel = None
        self.reloadList()
        self.reloadRecentWorlds()

    def _updateInstalls(self):
        for install in minecraftinstall.GetInstalls().installs:
            self.minecraftInstallBox.addItem(install.name)

        self.minecraftInstallBox.setCurrentIndex(minecraftinstall.GetInstalls().selectedInstallIndex())

        self._updateVersionsAndResourcePacks()

    def _updateVersionsAndResourcePacks(self):
        install = minecraftinstall.GetInstalls().getInstall(self.minecraftInstallBox.currentIndex())

        self.minecraftVersionBox.clear()
        for version in sorted(install.versions, reverse=True):
            self.minecraftVersionBox.addItem(version)

        self.resourcePackBox.clear()
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))
        for resourcePack in sorted(install.resourcePacks):
            self.resourcePackBox.addItem(resourcePack)

        self.saveDirs = install.getSaveDirs()
        self.savesFolderComboBox.clear()
        for filename in self.saveDirs:
            self.savesFolderComboBox.addItem(os.path.basename(os.path.dirname(filename)), (filename, None))
        for index, instance in enumerate(minecraftinstall.GetInstalls().instances):  # xxx instanceID?
            self.savesFolderComboBox.addItem(instance.name, (instance.saveFileDir, index))

    def getSelectedIVP(self):
        i = self.minecraftInstallBox.currentIndex()
        install = minecraftinstall.GetInstalls().getInstall(i)
        v = self.minecraftVersionBox.currentText()
        if self.resourcePackBox.currentIndex() > 0:
            p = self.resourcePackBox.currentText()
        else:
            p = None
        return install, v, p

    def reloadRecentWorlds(self):
        recentWorlds = RecentFilesSetting.value()
        self.recentWorldsMenu = QtGui.QMenu()

        def _triggered(f):
            def triggered():
                self.accept()
                self.editWorldClicked.emit(f)
            return triggered

        for filename in recentWorlds:
            try:
                displayName, lastPlayed = getWorldInfo(filename)
                action = self.recentWorldsMenu.addAction(displayName)
                action._editWorld = _triggered(filename)
                action.triggered.connect(action._editWorld)
            except EnvironmentError as e:
                log.exception("Failed to load world info")

        self.recentWorldsButton.setMenu(self.recentWorldsMenu)

    def reloadList(self):
        try:
            itemData = self.savesFolderComboBox.itemData(self.savesFolderComboBox.currentIndex())
            if itemData is None:
                log.error("No item selected in savesFolderComboBox!!(?)")
                return
            saveFileDir, instanceIndex = itemData
            if instanceIndex is not None:
                # disable version selector, update resource packs(?)
                pass
            if not os.path.isdir(saveFileDir):
                raise IOError(u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)".format(saveFileDir))

            log.info("Scanning %s for worlds...", saveFileDir)
            potentialWorlds = os.listdir(saveFileDir)
            potentialWorlds = [os.path.join(saveFileDir, p) for p in potentialWorlds]
            worldFiles = [p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)]

            self.worldListModel = WorldListModel(worldFiles)
            self.worldListView.setModel(self.worldListModel)

            if len(self.worldListModel.worlds):
                self.worldListView.setFocus()
                self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
                self.showWorld(self.worldListModel.worlds[0][0])

        except EnvironmentError as e:
            setWidgetError(self, e)

    def openWorldClicked(self):
        QtGui.qApp.chooseOpenWorld()

    _currentFilename = None

    def worldListItemClicked(self, index):
        filename = index.data()
        if filename != self._currentFilename:
            self._currentFilename = filename
            self.showWorld(filename)

    def worldListItemDoubleClicked(self, index):
        row = index.row()
        self.accept()
        self.editWorldClicked.emit(self.worldListModel.worlds[row][0])

    def showWorld(self, filename):
        self.removeWorldView()

        try:
            worldEditor = worldeditor.WorldEditor(filename, readonly=True)
            i, v, p = self.getSelectedIVP()
            resLoader = i.getResourceLoader(v, p)
            blockModels = BlockModels(worldEditor.blocktypes, resLoader)
            textureAtlas = TextureAtlas(worldEditor, resLoader, blockModels)

        except (EnvironmentError, LevelFormatError, zipfile.BadZipfile) as e:
            self.errorWidget = QtGui.QWidget()
            setWidgetError(self.errorWidget, e)
            self.stackedWidget.addWidget(self.errorWidget)
            self.stackedWidget.setCurrentWidget(self.errorWidget)

        else:

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim, textureAtlas))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                player = worldEditor.getPlayer()
                log.info("Centering on single-player player.")
            except PlayerNotFound:
                try:
                    center = worldEditor.worldSpawnPosition()
                    log.info("Centering on spawn position.")
                except AttributeError:
                    log.info("Centering on world center")
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)
            else:
                if player.dimName == dim.dimName:
                    center = Vector(*player.Position)
                    self.worldView.centerOnPoint(center)
                else:
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)

            self.worldView.centerOnPoint(center)
            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)
        self.stackedWidget.setCurrentWidget(worldView)

    def removeWorldView(self):
        self.stackedWidget.setCurrentWidget(self.blankWidget)
        QtGui.qApp.processEvents()  # force repaint of stackedWidget to hide old error widget
        if self.worldView:
            log.info("Removing view from WorldListWidget")
            self.worldView.textureAtlas.dispose()
            self.worldView.destroy()
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView.setParent(None)
            self.worldView = None
        if self.errorWidget:
            self.stackedWidget.removeWidget(self.errorWidget)
            self.errorWidget = None

        self.chunkLoader = None

    def hide(self):
        self.removeWorldView()
        super(WorldListWidget, self).hide()

    def close(self):
        self.removeWorldView()
        super(WorldListWidget, self).close()

    def reject(self):
        self.removeWorldView()
        super(WorldListWidget, self).reject()

    def showEvent(self, event):
        if self.worldListModel and len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])

        self.reloadRecentWorlds()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    @property
    def selectedWorldIndex(self):
        indexes = self.worldListView.selectedIndexes()
        if len(indexes):
            return indexes[0]

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.editWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def viewClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.viewWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def repairClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.repairWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def backupClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.backupWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateVersionsAndResourcePacks()
<|endoftext|>


<commit_before>#!/usr/bin/env python

import git_visitor_base
import git_repo_query
import git_push

import sys

def visitor_push(repos, options):

    ORIGINAL_COLOR = "\033[0m" # mvtodo: would be better to try to detect the terminal's current standard color

    report = []
    for rp in repos:

        remotes = git_repo_query.get_remotes(rp)
        if remotes is None:
            report.append("\033[31m%s: No remotes detected.\033[0m" % rp) # those colors are RED and WHITE, respectively. mvtodo: also change them here eventually
            continue

        remotes = git_visitor_base.filter_remotes(remotes, options)
        if remotes is None:
            report.append("\033[31m%s: Failed filtering remotes.\033[0m" % rp) # those colors are RED and WHITE, respectively. mvtodo: also change them here eventually
            continue

        branches = git_repo_query.get_branches(rp)
        if branches is None:
            report.append("\033[31m%s: No branches detected.\033[0m" % rp) # those colors are RED and WHITE, respectively. mvtodo: also change them here eventually
            continue

        branches = git_visitor_base.filter_branches(branches, options)
        if branches is None:
            report.append("\033[31m%s: Failed filtering branches.\033[0m" % rp) # those colors are RED and WHITE, respectively. mvtodo: also change them here eventually
            continue

        report_piece = git_push.do_push(rp, remotes, branches)
        for ri in report_piece:
            report.append(ri)

    print("\nRESULTS:")
    for p in report:
        print(p)
    print("%s\n" % ORIGINAL_COLOR) # reset terminal color

if __name__ == "__main__":

    filters = None
    if len(sys.argv) > 1:
        filters = sys.argv[1:]

    git_visitor_base.do_visit(None, filters, visitor_push)

<commit_msg>refactored visitor push to use visitor base's apply filter helper func<commit_after>#!/usr/bin/env python

import git_visitor_base
import git_repo_query
import git_push

import sys

def visitor_push(repos, options):

    ORIGINAL_COLOR = "\033[0m" # mvtodo: would be better to try to detect the terminal's current standard color

    report = []
    for rp in repos:

        try:
            remotes, branches = git_visitor_base.apply_filters(rp, options)
        except git_visitor_base.gvbexcept as gvbex:
            report.append("\033[31m%s: %s.\033[0m" % (gvbex.message, rp)) # those colors are RED and WHITE, respectively. mvtodo: also change them here eventually
            continue

        report_piece = git_push.do_push(rp, remotes, branches)
        for ri in report_piece:
            report.append(ri)

    print("\nRESULTS:")
    for p in report:
        print(p)
    print("%s\n" % ORIGINAL_COLOR) # reset terminal color

if __name__ == "__main__":

    filters = None
    if len(sys.argv) > 1:
        filters = sys.argv[1:]

    git_visitor_base.do_visit(None, filters, visitor_push)

<|endoftext|>