##// END OF EJS Templates
extensions: register functions always at loading extension (issue5601)...
extensions: register functions always at loading extension (issue5601) Before this patch, functions defined in extensions are registered via extra loaders only in _dispatch(). Therefore, loading extensions in other code paths like below omits registration of functions. - WSGI service - operation across repositories (e.g. subrepo) - test-duplicateoptions.py, using extensions.loadall() directly To register functions always at loading new extension, this patch moves implementation for extra loading from dispatch._dispatch() to extensions.loadall(). AFAIK, only commands module causes cyclic dependency between extensions module, but this patch imports all related modules just before extra loading in loadall(), in order to centralize them. This patch makes extensions.py depend on many other modules, even though extensions.py itself doesn't. It should be avoided if possible, but I don't have any better idea. Some other places like below aren't reasonable for extra loading, IMHO. - specific function in newly added module: existing callers of extensions.loadall() should invoke it, too - hg.repository() or so: no-repo commands aren't covered by this. BTW, this patch removes _loaded.add(name) on relocation, because dispatch._loaded is used only for extraloaders (for similar reason, "exts" variable is removed, too).

File last commit:

r32894:ec9ed269 default
r33052:45b0e9d0 default
Show More
test-ancestor.py
267 lines | 8.3 KiB | text/x-python | PythonLexer
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 from __future__ import absolute_import, print_function
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280
import binascii
import getopt
import math
import os
import random
import sys
import time
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 from mercurial.node import nullrev
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280 from mercurial import (
ancestor,
Gregory Szorc
debugcommands: move debugbuilddag...
r30402 debugcommands,
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280 hg,
Pulkit Goyal
py3: alias long to int and xrange to range in test-ancestor.py on Python 3
r32861 pycompat,
Yuya Nishihara
tests: alias ui as uimod in test-ancestor
r28774 ui as uimod,
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280 util,
)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331
Pulkit Goyal
py3: alias long to int and xrange to range in test-ancestor.py on Python 3
r32861 if pycompat.ispy3:
long = int
xrange = range
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 def buildgraph(rng, nodes=100, rootprob=0.05, mergeprob=0.2, prevprob=0.7):
'''nodes: total number of nodes in the graph
rootprob: probability that a new node (not 0) will be a root
mergeprob: probability that, excluding a root a node will be a merge
prevprob: probability that p1 will be the previous node
return value is a graph represented as an adjacency list.
'''
graph = [None] * nodes
for i in xrange(nodes):
if i == 0 or rng.random() < rootprob:
graph[i] = [nullrev]
elif i == 1:
graph[i] = [0]
elif rng.random() < mergeprob:
if i == 2 or rng.random() < prevprob:
# p1 is prev
p1 = i - 1
else:
p1 = rng.randrange(i - 1)
Pulkit Goyal
py3: pass range() into list() to get one explicitly...
r32893 p2 = rng.choice(list(range(0, p1)) + list(range(p1 + 1, i)))
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 graph[i] = [p1, p2]
elif rng.random() < prevprob:
graph[i] = [i - 1]
else:
graph[i] = [rng.randrange(i - 1)]
return graph
def buildancestorsets(graph):
ancs = [None] * len(graph)
for i in xrange(len(graph)):
Martin von Zweigbergk
cleanup: use set literals...
r32291 ancs[i] = {i}
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 if graph[i] == [nullrev]:
continue
for p in graph[i]:
ancs[i].update(ancs[p])
return ancs
Siddharth Agarwal
test-ancestor: move naive missing ancestor algorithm into a class...
r23335 class naiveincrementalmissingancestors(object):
def __init__(self, ancs, bases):
self.ancs = ancs
self.bases = set(bases)
Siddharth Agarwal
ancestor: add a way to add to bases of a missing ancestor object...
r23341 def addbases(self, newbases):
self.bases.update(newbases)
Siddharth Agarwal
ancestor: add a way to remove ancestors of bases from a given set...
r23342 def removeancestorsfrom(self, revs):
for base in self.bases:
if base != nullrev:
revs.difference_update(self.ancs[base])
revs.discard(nullrev)
Siddharth Agarwal
test-ancestor: move naive missing ancestor algorithm into a class...
r23335 def missingancestors(self, revs):
res = set()
for rev in revs:
if rev != nullrev:
res.update(self.ancs[rev])
for base in self.bases:
if base != nullrev:
res.difference_update(self.ancs[base])
return sorted(res)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331
def test_missingancestors(seed, rng):
# empirically observed to take around 1 second
graphcount = 100
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 testcount = 10
inccount = 10
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 nerrs = [0]
# the default mu and sigma give us a nice distribution of mostly
# single-digit counts (including 0) with some higher ones
def lognormrandom(mu, sigma):
return int(math.floor(rng.lognormvariate(mu, sigma)))
def samplerevs(nodes, mu=1.1, sigma=0.8):
count = min(lognormrandom(mu, sigma), len(nodes))
return rng.sample(nodes, count)
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 def err(seed, graph, bases, seq, output, expected):
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 if nerrs[0] == 0:
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print('seed:', hex(seed)[:-1], file=sys.stderr)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 if gerrs[0] == 0:
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print('graph:', graph, file=sys.stderr)
print('* bases:', bases, file=sys.stderr)
print('* seq: ', seq, file=sys.stderr)
print('* output: ', output, file=sys.stderr)
print('* expected:', expected, file=sys.stderr)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 nerrs[0] += 1
gerrs[0] += 1
for g in xrange(graphcount):
graph = buildgraph(rng)
ancs = buildancestorsets(graph)
gerrs = [0]
for _ in xrange(testcount):
# start from nullrev to include it as a possibility
graphnodes = range(nullrev, len(graph))
bases = samplerevs(graphnodes)
# fast algorithm
Siddharth Agarwal
ancestor.missingancestors: turn into a state-keeping class...
r23334 inc = ancestor.incrementalmissingancestors(graph.__getitem__, bases)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 # reference slow algorithm
Siddharth Agarwal
test-ancestor: move naive missing ancestor algorithm into a class...
r23335 naiveinc = naiveincrementalmissingancestors(ancs, bases)
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 seq = []
Siddharth Agarwal
ancestor: add a way to remove ancestors of bases from a given set...
r23342 revs = []
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 for _ in xrange(inccount):
Siddharth Agarwal
ancestor: add a way to add to bases of a missing ancestor object...
r23341 if rng.random() < 0.2:
newbases = samplerevs(graphnodes)
seq.append(('addbases', newbases))
inc.addbases(newbases)
naiveinc.addbases(newbases)
Siddharth Agarwal
ancestor: add a way to remove ancestors of bases from a given set...
r23342 if rng.random() < 0.4:
# larger set so that there are more revs to remove from
revs = samplerevs(graphnodes, mu=1.5)
seq.append(('removeancestorsfrom', revs))
hrevs = set(revs)
rrevs = set(revs)
inc.removeancestorsfrom(hrevs)
naiveinc.removeancestorsfrom(rrevs)
if hrevs != rrevs:
err(seed, graph, bases, seq, sorted(hrevs),
sorted(rrevs))
else:
revs = samplerevs(graphnodes)
seq.append(('missingancestors', revs))
h = inc.missingancestors(revs)
r = naiveinc.missingancestors(revs)
if h != r:
err(seed, graph, bases, seq, h, r)
Siddharth Agarwal
ancestor: move missingancestors doctest out into a separate file...
r18079
# graph is a dict of child->parent adjacency lists for this graph:
# o 13
# |
# | o 12
# | |
# | | o 11
# | | |\
# | | | | o 10
# | | | | |
# | o---+ | 9
# | | | | |
# o | | | | 8
# / / / /
# | | o | 7
# | | | |
# o---+ | 6
# / / /
# | | o 5
# | |/
# | o 4
# | |
# o | 3
# | |
# | o 2
# |/
# o 1
# |
# o 0
graph = {0: [-1], 1: [0], 2: [1], 3: [1], 4: [2], 5: [4], 6: [4],
7: [4], 8: [-1], 9: [6, 7], 10: [5], 11: [3, 7], 12: [9],
13: [8]}
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 def genlazyancestors(revs, stoprev=0, inclusive=False):
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print(("%% lazy ancestor set for %s, stoprev = %s, inclusive = %s" %
(revs, stoprev, inclusive)))
Siddharth Agarwal
ancestor.lazyancestors: take parentrevs function rather than changelog...
r23328 return ancestor.lazyancestors(graph.get, revs, stoprev=stoprev,
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 inclusive=inclusive)
def printlazyancestors(s, l):
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print('membership: %r' % [n for n in l if n in s])
print('iteration: %r' % list(s))
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091
def test_lazyancestors():
# Empty revs
s = genlazyancestors([])
printlazyancestors(s, [3, 0, -1])
# Standard example
s = genlazyancestors([11, 13])
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
Pierre-Yves David
test-ancestor: add a test for `ancestor` with ancestry within the initset...
r22355 # Standard with ancestry in the initial set (1 is ancestor of 3)
s = genlazyancestors([1, 3])
printlazyancestors(s, [1, -1, 0])
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 # Including revs
s = genlazyancestors([11, 13], inclusive=True)
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
# Test with stoprev
s = genlazyancestors([11, 13], stoprev=6)
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
s = genlazyancestors([11, 13], stoprev=6, inclusive=True)
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504
# The C gca algorithm requires a real repo. These are textual descriptions of
Mads Kiilerich
spelling: fixes from spell checker
r21024 # DAGs that have been known to be problematic.
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 dagtests = [
'+2*2*2/*3/2',
'+3*3/*2*2/*4*4/*4/2*4/2*2',
]
def test_gca():
Yuya Nishihara
ui: factor out ui.load() to create a ui without loading configs (API)...
r30559 u = uimod.ui.load()
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 for i, dag in enumerate(dagtests):
Pulkit Goyal
py3: pass the path in hg.repository() as bytes...
r32894 repo = hg.repository(u, b'gca%d' % i, create=1)
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 cl = repo.changelog
if not util.safehasattr(cl.index, 'ancestors'):
# C version not available
return
Gregory Szorc
debugcommands: move debugbuilddag...
r30402 debugcommands.debugbuilddag(u, repo, dag)
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 # Compare the results of the Python and C versions. This does not
# include choosing a winner when more than one gca exists -- we make
# sure both return exactly the same set of gcas.
for a in cl:
for b in cl:
cgcas = sorted(cl.index.ancestors(a, b))
pygcas = sorted(ancestor.ancestors(cl.parentrevs, a, b))
if cgcas != pygcas:
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print("test_gca: for dag %s, gcas for %d, %d:"
% (dag, a, b))
print(" C returned: %s" % cgcas)
print(" Python returned: %s" % pygcas)
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504
Siddharth Agarwal
test-ancestor: define a main function...
r23330 def main():
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 seed = None
opts, args = getopt.getopt(sys.argv[1:], 's:', ['seed='])
for o, a in opts:
if o in ('-s', '--seed'):
seed = long(a, base=0) # accepts base 10 or 16 strings
if seed is None:
try:
seed = long(binascii.hexlify(os.urandom(16)), 16)
except AttributeError:
seed = long(time.time() * 1000)
rng = random.Random(seed)
test_missingancestors(seed, rng)
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 test_lazyancestors()
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 test_gca()
Siddharth Agarwal
test-ancestor: define a main function...
r23330
if __name__ == '__main__':
main()