<commit_before>import binascii, hashlib

b = 256
q = 2**255 - 19
L = 2**252 + 27742317777372353535851937790883648493

def inv(x):
    return pow(x, q-2, q)

d = -121665 * inv(121666)
I = pow(2,(q-1)//4,q)

def xrecover(y):
    xx = (y*y-1) * inv(d*y*y+1)
    x = pow(xx,(q+3)//8,q)
    if (x*x - xx) % q != 0: x = (x*I) % q
    if x % 2 != 0: x = q-x
    return x

By = 4 * inv(5)
Bx = xrecover(By)
B = [Bx % q,By % q]

# Extended Coordinates: x=X/Z, y=Y/Z, x*y=T/Z
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html

def xform_affine_to_extended(pt):
    (x, y) = pt
    return (x%q, y%q, 1, (x*y)%q) # (X,Y,Z,T)

def xform_extended_to_affine(pt):
    (x, y, z, _) = pt
    return ((x*inv(z))%q, (y*inv(z))%q)

def double_extended(pt): # extended->extended
    # dbl-2008-hwcd
    (X1, Y1, Z1, _) = pt
    A = (X1*X1)
    B = (Y1*Y1)
    C = (2*Z1*Z1)
    D = (-A) % q
    J = (X1+Y1) % q
    E = (J*J-A-B) % q
    G = (D+B) % q
    F = (G-C) % q
    H = (D-B) % q
    X3 = (E*F) % q
    Y3 = (G*H) % q
    Z3 = (F*G) % q
    T3 = (E*H) % q
    return (X3, Y3, Z3, T3)

def add_extended(pt1, pt2): # extended->extended
    # add-2008-hwcd-3 . Slightly slower than add-2008-hwcd-4, but -3 is
    # unified, so it's safe for general-purpose addition..
    (X1, Y1, Z1, T1) = pt1
    (X2, Y2, Z2, T2) = pt2
    A = ((Y1-X1)*(Y2-X2)) % q
    B = ((Y1+X1)*(Y2+X2)) % q
    C = T1*(2*d)*T2 % q
    D = Z1*2*Z2 % q
    E = (B-A) % q
    F = (D-C) % q
    G = (D+C) % q
    H = (B+A) % q
    X3 = (E*F) % q
    Y3 = (G*H) % q
    T3 = (E*H) % q
    Z3 = (F*G) % q
    return (X3, Y3, Z3, T3)

def scalarmult_extended_safe_slow(pt, n):
    # this form is slightly slower, but tolerates arbitrary points, including
    # those which are not in the main 1*L subgroup. This includes points of
    # order 1 (the neutral element Zero), 2, 4, and 8.
    assert n >= 0
    if n==0:
        return xform_affine_to_extended((0,1))
    _ = double_extended(scalarmult_extended_safe_slow(pt, n>>1))
    return add_extended(_, pt) if n&1 else _

def _add_extended_nonunfied(pt1, pt2): # extended->extended
    # add-2008-hwcd-4 : NOT unified, only for pt1!=pt2. About 10% faster than
    # the (unified) add-2008-hwcd-3, and safe to use inside scalarmult if you
    # aren't using points of order 1/2/4/8
    (X1, Y1, Z1, T1) = pt1
    (X2, Y2, Z2, T2) = pt2
    A = ((Y1-X1)*(Y2+X2)) % q
    B = ((Y1+X1)*(Y2-X2)) % q
    C = (Z1*2*T2) % q
    D = (T1*2*Z2) % q
    E = (D+C) % q
    F = (B-A) % q
    G = (B+A) % q
    H = (D-C) % q
    X3 = (E*F) % q
    Y3 = (G*H) % q
    Z3 = (F*G) % q
    T3 = (E*H) % q
    return (X3, Y3, Z3, T3)

def scalarmult_extended(pt, n): # extended->extended
    # This form only works properly when given points that are a member of
    # the main 1*L subgroup. It will give incorrect answers when called with
    # the points of order 1/2/4/8, including point Zero. (it will also work
    # properly when given points of order 2*L/4*L/8*L)
    assert n >= 0
    if n==0:
        return xform_affine_to_extended((0,1))
    _ = double_extended(scalarmult_extended(pt, n>>1))
    return _add_extended_nonunfied(_, pt) if n&1 else _

# points are encoded as 32-bytes little-endian, b255 is sign, b2b1b0 are 0

def encodepoint(P):
    x = P[0]
    y = P[1]
    # MSB of output equals x.b0 (=x&1)
    # rest of output is little-endian y
    assert 0 <= y < (1<<255) # always < 0x7fff..ff
    if x & 1:
        y += 1<<255
    return binascii.unhexlify("%064x" % y)[::-1]

def isoncurve(P):
    x = P[0]
    y = P[1]
    return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0

class NotOnCurve(Exception):
    pass

def decodepoint(s):
    unclamped = int(binascii.hexlify(s[:32][::-1]), 16)
    clamp = (1 << 255) - 1
    y = unclamped & clamp # clear MSB
    x = xrecover(y)
    if bool(x & 1) != bool(unclamped & (1<<255)): x = q-x
    P = [x,y]
    if not isoncurve(P): raise NotOnCurve("decoding point that is not on curve")
    return P

# scalars are encoded as 32-bytes little-endian

def bytes_to_scalar(s):
    assert len(s) == 32, len(s)
    return int(binascii.hexlify(s[::-1]), 16)

def bytes_to_clamped_scalar(s):
    # Ed25519 private keys clamp the scalar to ensure two things:
    #   1: integer value is in L/2 .. L, to avoid small-logarithm
    #      non-wraparaound
    #   2: low-order 3 bits are zero, so a small-subgroup attack won't learn
    #      any information
    # set the top two bits to 01, and the bottom three to 000
    a_unclamped = bytes_to_scalar(s)
    AND_CLAMP = (1<<254) - 1 - 7
    OR_CLAMP = (1<<254)
    a_clamped = (a_unclamped & AND_CLAMP) | OR_CLAMP
    return a_clamped

def random_scalar(entropy_f): # 0..L-1 inclusive
    # reduce the bias to a safe level by generating 256 extra bits
    oversized = int(binascii.hexlify(entropy_f(32+32)), 16)
    return oversized % L

def password_to_scalar(pw):
    oversized = hashlib.sha512(pw).digest()
    return int(binascii.hexlify(oversized), 16) % L

def scalar_to_bytes(y):
    y = y % L
    assert 0 <= y < 2**256
    return binascii.unhexlify("%064x" % y)[::-1]

# Elements, of various orders

def is_extended_zero(XYTZ):
    # catch Zero
    (X, Y, Z, T) = XYTZ
    Y = Y % q
    Z = Z % q
    if X==0 and Y==Z and Y!=0:
        return True
    return False

class ElementOfUnknownGroup:
    # This is used for points of order 2,4,8,2*L,4*L,8*L
    def __init__(self, XYTZ):
        assert isinstance(XYTZ, tuple)
        assert len(XYTZ) == 4
        self.XYTZ = XYTZ

    def add(self, other):
        sum_XYTZ = add_extended(self.XYTZ, other.XYTZ)
        if is_extended_zero(sum_XYTZ):
            return Zero
        return ElementOfUnknownGroup(sum_XYTZ)

    def scalarmult(self, s):
        assert s >= 0
        product = scalarmult_extended_safe_slow(self.XYTZ, s)
        return ElementOfUnknownGroup(product)

    def to_bytes(self):
        return encodepoint(xform_extended_to_affine(self.XYTZ))
    def __eq__(self, other):
        return self.to_bytes() == other.to_bytes()
    def __ne__(self, other):
        return not self == other

class Element(ElementOfUnknownGroup):
    # this only holds elements in the main 1*L subgroup. It never holds Zero,
    # or elements of order 1/2/4/8, or 2*L/4*L/8*L.

    def add(self, other):
        sum_element = ElementOfUnknownGroup.add(self, other)
        if sum_element is Zero:
            return sum_element
        if isinstance(other, Element):
            # adding two subgroup elements results in another subgroup
            # element, or Zero, and we've already excluded Zero
            return Element(sum_element.XYTZ)
        # not necessarily a subgroup member, so assume not
        return sum_element

    def scalarmult(self, s):
        # scalarmult of subgroup members can be done modulo the subgroup
        # order, and using the faster non-unified function.
        s = s % L
        # scalarmult(s=0) gets you Zero
        if s == 0:
            return Zero
        # scalarmult(s=1) gets you self, which is a subgroup member
        # scalarmult(s<grouporder) gets you a different subgroup member
        return Element(scalarmult_extended(self.XYTZ, s))

    # negation and subtraction only make sense for the main subgroup
    def negate(self):
        # slow. Prefer e.scalarmult(-pw) to e.scalarmult(pw).negate()
        return Element(scalarmult_extended(self.XYTZ, L-2))
    def subtract(self, other):
        return self.add(other.negate())

class _ZeroElement(ElementOfUnknownGroup):
    def add(self, other):
        return other # zero+anything = anything
    def scalarmult(self, s):
        return self # zero*anything = zero
    def negate(self):
        return self # -zero = zero
    def subtract(self, other):
        return self.add(other.negate())

Base = Element(xform_affine_to_extended(B))
Zero = _ZeroElement(xform_affine_to_extended((0,1))) # the neutral (identity) element

_zero_bytes = Zero.to_bytes()

def arbitrary_element(seed): # unknown DL
    # TODO: if we don't need uniformity, maybe use just sha256 here?
    hseed = hashlib.sha512(seed).digest()
    y = int(binascii.hexlify(hseed), 16) % q
    while True:
        x = xrecover(y)
        Pa = [x,y] # no attempt to use both "positive" and "negative" X

        # only about 50% of Y coordinates map to valid curve points (I think
        # the other half give you points on the "twist").
        if isoncurve(Pa):
            P = ElementOfUnknownGroup(xform_affine_to_extended(Pa))
            # even if the point is on our curve, it may not be in our
            # particular (order=L) subgroup. The curve has order 8*L, so an
            # arbitrary point could have order 1,2,4,8,1*L,2*L,4*L,8*L
            # (everything which divides the group order).

            # [I MAY BE COMPLETELY WRONG ABOUT THIS, but my brief statistical
            # tests suggest it's not too far off] There are phi(x) points
            # with order x, so:
            #  1 element of order 1: [(x=0,y=1)=Zero]
            #  1 element of order 2 [(x=0,y=-1)]
            #  2 elements of order 4
            #  4 elements of order 8
            #  L-1 elements of order L (including Base)
            #  L-1 elements of order 2*L
            #  2*(L-1) elements of order 4*L
            #  4*(L-1) elements of order 8*L

            # So 50% of random points will have order 8*L, 25% will have
            # order 4*L, 13% order 2*L, and 13% will have our desired order
            # 1*L (and a vanishingly small fraction will have 1/2/4/8). If we
            # multiply any of the 8*L points by 2, we're sure to get an 4*L
            # point (and multiplying a 4*L point by 2 gives us a 2*L point,
            # and so on). Multiplying a 1*L point by 2 gives us a different
            # 1*L point. So multiplying by 8 gets us from almost any point
            # into a uniform point on the correct 1*L subgroup.

            P8 = P.scalarmult(8)

            # if we got really unlucky and picked one of the 8 low-order
            # points, multiplying by 8 will get us to the identity (Zero),
            # which we check for explicitly.
            if is_extended_zero(P8.XYTZ):
                continue

            # Test that we're finally in the right group. We want to
            # scalarmult by L, and we want to *not* use the trick in
            # Group.scalarmult() which does x%L, because that would bypass
            # the check we care about. P is still an _ElementOfUnknownGroup,
            # which doesn't use x%L because that's not correct for points
            # outside the main group.
            assert is_extended_zero(P8.scalarmult(L).XYTZ)

            return Element(P8.XYTZ)
        # increment our Y and try again until we find a valid point
        y = (y + 1) % q
    # never reached

def bytes_to_unknown_group_element(bytes):
    # this accepts all elements, including Zero and wrong-subgroup ones
    if bytes == _zero_bytes:
        return Zero
    XYTZ = xform_affine_to_extended(decodepoint(bytes))
    return ElementOfUnknownGroup(XYTZ)

def bytes_to_element(bytes):
    # this strictly only accepts elements in the right subgroup
    P = bytes_to_unknown_group_element(bytes)
    if P is Zero:
        raise ValueError("element was Zero")
    if not is_extended_zero(P.scalarmult(L).XYTZ):
        raise ValueError("element is not in the right group")
    # the point is in the expected 1*L subgroup, not in the 2/4/8 groups,
    # or in the 2*L/4*L/8*L groups. Promote it to a correct-group Element.
    return Element(P.XYTZ)
<commit_msg>remove unused 'b' (bit length of scalars/points)<commit_after>import binascii, hashlib

q = 2**255 - 19
L = 2**252 + 27742317777372353535851937790883648493

def inv(x):
    return pow(x, q-2, q)

d = -121665 * inv(121666)
I = pow(2,(q-1)//4,q)

def xrecover(y):
    xx = (y*y-1) * inv(d*y*y+1)
    x = pow(xx,(q+3)//8,q)
    if (x*x - xx) % q != 0: x = (x*I) % q
    if x % 2 != 0: x = q-x
    return x

By = 4 * inv(5)
Bx = xrecover(By)
B = [Bx % q,By % q]

# Extended Coordinates: x=X/Z, y=Y/Z, x*y=T/Z
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html

def xform_affine_to_extended(pt):
    (x, y) = pt
    return (x%q, y%q, 1, (x*y)%q) # (X,Y,Z,T)

def xform_extended_to_affine(pt):
    (x, y, z, _) = pt
    return ((x*inv(z))%q, (y*inv(z))%q)

def double_extended(pt): # extended->extended
    # dbl-2008-hwcd
    (X1, Y1, Z1, _) = pt
    A = (X1*X1)
    B = (Y1*Y1)
    C = (2*Z1*Z1)
    D = (-A) % q
    J = (X1+Y1) % q
    E = (J*J-A-B) % q
    G = (D+B) % q
    F = (G-C) % q
    H = (D-B) % q
    X3 = (E*F) % q
    Y3 = (G*H) % q
    Z3 = (F*G) % q
    T3 = (E*H) % q
    return (X3, Y3, Z3, T3)

def add_extended(pt1, pt2): # extended->extended
    # add-2008-hwcd-3 . Slightly slower than add-2008-hwcd-4, but -3 is
    # unified, so it's safe for general-purpose addition..
    (X1, Y1, Z1, T1) = pt1
    (X2, Y2, Z2, T2) = pt2
    A = ((Y1-X1)*(Y2-X2)) % q
    B = ((Y1+X1)*(Y2+X2)) % q
    C = T1*(2*d)*T2 % q
    D = Z1*2*Z2 % q
    E = (B-A) % q
    F = (D-C) % q
    G = (D+C) % q
    H = (B+A) % q
    X3 = (E*F) % q
    Y3 = (G*H) % q
    T3 = (E*H) % q
    Z3 = (F*G) % q
    return (X3, Y3, Z3, T3)

def scalarmult_extended_safe_slow(pt, n):
    # this form is slightly slower, but tolerates arbitrary points, including
    # those which are not in the main 1*L subgroup. This includes points of
    # order 1 (the neutral element Zero), 2, 4, and 8.
    assert n >= 0
    if n==0:
        return xform_affine_to_extended((0,1))
    _ = double_extended(scalarmult_extended_safe_slow(pt, n>>1))
    return add_extended(_, pt) if n&1 else _

def _add_extended_nonunfied(pt1, pt2): # extended->extended
    # add-2008-hwcd-4 : NOT unified, only for pt1!=pt2. About 10% faster than
    # the (unified) add-2008-hwcd-3, and safe to use inside scalarmult if you
    # aren't using points of order 1/2/4/8
    (X1, Y1, Z1, T1) = pt1
    (X2, Y2, Z2, T2) = pt2
    A = ((Y1-X1)*(Y2+X2)) % q
    B = ((Y1+X1)*(Y2-X2)) % q
    C = (Z1*2*T2) % q
    D = (T1*2*Z2) % q
    E = (D+C) % q
    F = (B-A) % q
    G = (B+A) % q
    H = (D-C) % q
    X3 = (E*F) % q
    Y3 = (G*H) % q
    Z3 = (F*G) % q
    T3 = (E*H) % q
    return (X3, Y3, Z3, T3)

def scalarmult_extended(pt, n): # extended->extended
    # This form only works properly when given points that are a member of
    # the main 1*L subgroup. It will give incorrect answers when called with
    # the points of order 1/2/4/8, including point Zero. (it will also work
    # properly when given points of order 2*L/4*L/8*L)
    assert n >= 0
    if n==0:
        return xform_affine_to_extended((0,1))
    _ = double_extended(scalarmult_extended(pt, n>>1))
    return _add_extended_nonunfied(_, pt) if n&1 else _

# points are encoded as 32-bytes little-endian, b255 is sign, b2b1b0 are 0

def encodepoint(P):
    x = P[0]
    y = P[1]
    # MSB of output equals x.b0 (=x&1)
    # rest of output is little-endian y
    assert 0 <= y < (1<<255) # always < 0x7fff..ff
    if x & 1:
        y += 1<<255
    return binascii.unhexlify("%064x" % y)[::-1]

def isoncurve(P):
    x = P[0]
    y = P[1]
    return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0

class NotOnCurve(Exception):
    pass

def decodepoint(s):
    unclamped = int(binascii.hexlify(s[:32][::-1]), 16)
    clamp = (1 << 255) - 1
    y = unclamped & clamp # clear MSB
    x = xrecover(y)
    if bool(x & 1) != bool(unclamped & (1<<255)): x = q-x
    P = [x,y]
    if not isoncurve(P): raise NotOnCurve("decoding point that is not on curve")
    return P

# scalars are encoded as 32-bytes little-endian

def bytes_to_scalar(s):
    assert len(s) == 32, len(s)
    return int(binascii.hexlify(s[::-1]), 16)

def bytes_to_clamped_scalar(s):
    # Ed25519 private keys clamp the scalar to ensure two things:
    #   1: integer value is in L/2 .. L, to avoid small-logarithm
    #      non-wraparaound
    #   2: low-order 3 bits are zero, so a small-subgroup attack won't learn
    #      any information
    # set the top two bits to 01, and the bottom three to 000
    a_unclamped = bytes_to_scalar(s)
    AND_CLAMP = (1<<254) - 1 - 7
    OR_CLAMP = (1<<254)
    a_clamped = (a_unclamped & AND_CLAMP) | OR_CLAMP
    return a_clamped

def random_scalar(entropy_f): # 0..L-1 inclusive
    # reduce the bias to a safe level by generating 256 extra bits
    oversized = int(binascii.hexlify(entropy_f(32+32)), 16)
    return oversized % L

def password_to_scalar(pw):
    oversized = hashlib.sha512(pw).digest()
    return int(binascii.hexlify(oversized), 16) % L

def scalar_to_bytes(y):
    y = y % L
    assert 0 <= y < 2**256
    return binascii.unhexlify("%064x" % y)[::-1]

# Elements, of various orders

def is_extended_zero(XYTZ):
    # catch Zero
    (X, Y, Z, T) = XYTZ
    Y = Y % q
    Z = Z % q
    if X==0 and Y==Z and Y!=0:
        return True
    return False

class ElementOfUnknownGroup:
    # This is used for points of order 2,4,8,2*L,4*L,8*L
    def __init__(self, XYTZ):
        assert isinstance(XYTZ, tuple)
        assert len(XYTZ) == 4
        self.XYTZ = XYTZ

    def add(self, other):
        sum_XYTZ = add_extended(self.XYTZ, other.XYTZ)
        if is_extended_zero(sum_XYTZ):
            return Zero
        return ElementOfUnknownGroup(sum_XYTZ)

    def scalarmult(self, s):
        assert s >= 0
        product = scalarmult_extended_safe_slow(self.XYTZ, s)
        return ElementOfUnknownGroup(product)

    def to_bytes(self):
        return encodepoint(xform_extended_to_affine(self.XYTZ))
    def __eq__(self, other):
        return self.to_bytes() == other.to_bytes()
    def __ne__(self, other):
        return not self == other

class Element(ElementOfUnknownGroup):
    # this only holds elements in the main 1*L subgroup. It never holds Zero,
    # or elements of order 1/2/4/8, or 2*L/4*L/8*L.

    def add(self, other):
        sum_element = ElementOfUnknownGroup.add(self, other)
        if sum_element is Zero:
            return sum_element
        if isinstance(other, Element):
            # adding two subgroup elements results in another subgroup
            # element, or Zero, and we've already excluded Zero
            return Element(sum_element.XYTZ)
        # not necessarily a subgroup member, so assume not
        return sum_element

    def scalarmult(self, s):
        # scalarmult of subgroup members can be done modulo the subgroup
        # order, and using the faster non-unified function.
        s = s % L
        # scalarmult(s=0) gets you Zero
        if s == 0:
            return Zero
        # scalarmult(s=1) gets you self, which is a subgroup member
        # scalarmult(s<grouporder) gets you a different subgroup member
        return Element(scalarmult_extended(self.XYTZ, s))

    # negation and subtraction only make sense for the main subgroup
    def negate(self):
        # slow. Prefer e.scalarmult(-pw) to e.scalarmult(pw).negate()
        return Element(scalarmult_extended(self.XYTZ, L-2))
    def subtract(self, other):
        return self.add(other.negate())

class _ZeroElement(ElementOfUnknownGroup):
    def add(self, other):
        return other # zero+anything = anything
    def scalarmult(self, s):
        return self # zero*anything = zero
    def negate(self):
        return self # -zero = zero
    def subtract(self, other):
        return self.add(other.negate())

Base = Element(xform_affine_to_extended(B))
Zero = _ZeroElement(xform_affine_to_extended((0,1))) # the neutral (identity) element

_zero_bytes = Zero.to_bytes()

def arbitrary_element(seed): # unknown DL
    # TODO: if we don't need uniformity, maybe use just sha256 here?
    hseed = hashlib.sha512(seed).digest()
    y = int(binascii.hexlify(hseed), 16) % q
    while True:
        x = xrecover(y)
        Pa = [x,y] # no attempt to use both "positive" and "negative" X

        # only about 50% of Y coordinates map to valid curve points (I think
        # the other half give you points on the "twist").
        if isoncurve(Pa):
            P = ElementOfUnknownGroup(xform_affine_to_extended(Pa))
            # even if the point is on our curve, it may not be in our
            # particular (order=L) subgroup. The curve has order 8*L, so an
            # arbitrary point could have order 1,2,4,8,1*L,2*L,4*L,8*L
            # (everything which divides the group order).

            # [I MAY BE COMPLETELY WRONG ABOUT THIS, but my brief statistical
            # tests suggest it's not too far off] There are phi(x) points
            # with order x, so:
            #  1 element of order 1: [(x=0,y=1)=Zero]
            #  1 element of order 2 [(x=0,y=-1)]
            #  2 elements of order 4
            #  4 elements of order 8
            #  L-1 elements of order L (including Base)
            #  L-1 elements of order 2*L
            #  2*(L-1) elements of order 4*L
            #  4*(L-1) elements of order 8*L

            # So 50% of random points will have order 8*L, 25% will have
            # order 4*L, 13% order 2*L, and 13% will have our desired order
            # 1*L (and a vanishingly small fraction will have 1/2/4/8). If we
            # multiply any of the 8*L points by 2, we're sure to get an 4*L
            # point (and multiplying a 4*L point by 2 gives us a 2*L point,
            # and so on). Multiplying a 1*L point by 2 gives us a different
            # 1*L point. So multiplying by 8 gets us from almost any point
            # into a uniform point on the correct 1*L subgroup.

            P8 = P.scalarmult(8)

            # if we got really unlucky and picked one of the 8 low-order
            # points, multiplying by 8 will get us to the identity (Zero),
            # which we check for explicitly.
            if is_extended_zero(P8.XYTZ):
                continue

            # Test that we're finally in the right group. We want to
            # scalarmult by L, and we want to *not* use the trick in
            # Group.scalarmult() which does x%L, because that would bypass
            # the check we care about. P is still an _ElementOfUnknownGroup,
            # which doesn't use x%L because that's not correct for points
            # outside the main group.
            assert is_extended_zero(P8.scalarmult(L).XYTZ)

            return Element(P8.XYTZ)
        # increment our Y and try again until we find a valid point
        y = (y + 1) % q
    # never reached

def bytes_to_unknown_group_element(bytes):
    # this accepts all elements, including Zero and wrong-subgroup ones
    if bytes == _zero_bytes:
        return Zero
    XYTZ = xform_affine_to_extended(decodepoint(bytes))
    return ElementOfUnknownGroup(XYTZ)

def bytes_to_element(bytes):
    # this strictly only accepts elements in the right subgroup
    P = bytes_to_unknown_group_element(bytes)
    if P is Zero:
        raise ValueError("element was Zero")
    if not is_extended_zero(P.scalarmult(L).XYTZ):
        raise ValueError("element is not in the right group")
    # the point is in the expected 1*L subgroup, not in the 2/4/8 groups,
    # or in the 2*L/4*L/8*L groups. Promote it to a correct-group Element.
    return Element(P.XYTZ)
<|endoftext|>


<commit_before>from tastypie.resources import ALL, ALL_WITH_RELATIONS
from tastypie import fields
from tastypie.resources import ModelResource

from django.http import HttpResponse

from .models import CaseVersion, Case, Suite, CaseStep, SuiteCase
from ..environments.api import EnvironmentResource
from ..core.api import ProductVersionResource
from ..tags.api import TagResource

class SuiteResource(ModelResource):

    class Meta:
        queryset = Suite.objects.all()
        fields = ["name"]
        filtering = {
            "name": ALL,
            }

class CaseResource(ModelResource):
    suites = fields.ToManyField(SuiteResource, "suites", full=True)

    class Meta:
        queryset = Case.objects.all()
        fields= ["id", "suites"]
        filtering = {
            "suites": ALL_WITH_RELATIONS,
            }

class CaseStepResource(ModelResource):

    class Meta:
        queryset = CaseStep.objects.all()
        fields = ["instruction", "expected"]

class CaseVersionResource(ModelResource):

    case = fields.ForeignKey(CaseResource, "case", full=True)
    steps = fields.ToManyField(CaseStepResource, "steps", full=True)
    environments = fields.ToManyField(EnvironmentResource, "environments", full=True)
    productversion = fields.ForeignKey(ProductVersionResource, "productversion")
    tags = fields.ToManyField(TagResource, "tags", full=True)

    class Meta:
        queryset = CaseVersion.objects.all()
        list_allowed_methods = ['get']
        fields = ["id", "name", "description", "case"]
        filtering = {
            "environments": ALL,
            "productversion": ALL_WITH_RELATIONS,
            "case": ALL_WITH_RELATIONS,
            "tags": ALL_WITH_RELATIONS,
            }

class SuiteCaseSelectionResource(ModelResource):
    """
    Specialty end-point for an AJAX call in the Suite form multi-select widget
    for selecting cases.
    """

    case = fields.ForeignKey(CaseResource, "case")
    productversion = fields.ForeignKey(ProductVersionResource, "productversion")
    tags = fields.ToManyField(TagResource, "tags", full=True)

    class Meta:
        queryset = CaseVersion.objects.filter(latest=True).select_related(
            "case",
            "productversion",
            )
        # @@@ Django 1.4 - use prefetch_related on the tag field
        list_allowed_methods = ['get']
        fields = ["id", "name"]
        filtering = {
            "productversion": ALL_WITH_RELATIONS,
            }

    def get_list(self, request, **kwargs):
        """
        Save the suitecases orders so we don't have to query for each case.

        @@@ Django 1.4 - shouldn't need this when we have prefetch_related
        in Django 1.4
        """
        if "for_suite" in request.GET.keys():
             sc = SuiteCase.objects.filter(suite__id=request.GET["for_suite"])
             self.suitecases_cache = dict((x.case_id, x.order) for x in sc)
        return super(SuiteCaseSelectionResource, self).get_list(
            request, **kwargs)

    def dehydrate(self, bundle):
        """Add some convenience fields to the return JSON."""

        case = bundle.obj.case
        bundle.data["case_id"] = unicode(case.id)
        bundle.data["product_id"] = unicode(case.product_id)
        bundle.data["product"] = {"id": unicode(case.product_id)}

        try:
            bundle.data["created_by"] = {
                "id": unicode(case.created_by.id),
                "username": case.created_by.username,
                }
        except AttributeError:
            bundle.data["created_by"] = None

        try:
            bundle.data["order"] = self.suitecases_cache[case.id]
        except (KeyError, TypeError, AttributeError):
            # suitecases_cache may not be defined, or may be none
            # or may just not contain the id we're looking for.
            # either way, set it to None
            bundle.data["order"] = None

        return bundle

    def create_response(self, request, data, response_class=HttpResponse, **response_kwargs):
        """
        Remove the "cached" runsuites because we're done with it.

        @@@ Django 1.4 - shouldn't need this when we have prefetch_related
        in Django 1.4
        """
        self.suitecases_cache = None
        return super(SuiteCaseSelectionResource, self).create_response(
            request, data, response_class=HttpResponse, **response_kwargs)

    def alter_list_data_to_serialize(self, request, data):
        """Split list of cases between included and excluded from the suite"""
        included = [x for x in data["objects"] if x.data["order"] is not None]
        included = sorted(included, key=lambda k: k.data["order"])
        excluded =  [x for x in data["objects"] if x.data["order"] is None]
        data["objects"] = {"selected": included, "unselected": excluded}
        return data<commit_msg>create, edit, list, search, and delete suites<commit_after>from tastypie.resources import ALL, ALL_WITH_RELATIONS
from tastypie import fields
from tastypie.resources import ModelResource

from django.http import HttpResponse

from ..core.api import (ProductVersionResource, ProductResource,
                        ReportResultsAuthorization, MTApiKeyAuthentication)
from .models import CaseVersion, Case, Suite, CaseStep, SuiteCase
from ..environments.api import EnvironmentResource
from ..tags.api import TagResource

class SuiteResource(ModelResource):

    product = fields.ToOneField(ProductResource, 'product')

    class Meta:
        queryset = Suite.objects.all()
        fields = ["name", "product", "description", "status", "id"]
        list_allowed_methods = ["get", "post", "delete"]
        filtering = {
            "name": ALL,
            "product": ALL_WITH_RELATIONS,
            }
        authentication = MTApiKeyAuthentication()
        authorization = ReportResultsAuthorization()

class CaseResource(ModelResource):
    suites = fields.ToManyField(SuiteResource, "suites", full=True)

    class Meta:
        queryset = Case.objects.all()
        fields= ["id", "suites"]
        filtering = {
            "suites": ALL_WITH_RELATIONS,
            }

class CaseStepResource(ModelResource):

    class Meta:
        queryset = CaseStep.objects.all()
        fields = ["instruction", "expected"]

class CaseVersionResource(ModelResource):

    case = fields.ForeignKey(CaseResource, "case", full=True)
    steps = fields.ToManyField(CaseStepResource, "steps", full=True)
    environments = fields.ToManyField(EnvironmentResource, "environments", full=True)
    productversion = fields.ForeignKey(ProductVersionResource, "productversion")
    tags = fields.ToManyField(TagResource, "tags", full=True)

    class Meta:
        queryset = CaseVersion.objects.all()
        list_allowed_methods = ['get']
        fields = ["id", "name", "description", "case"]
        filtering = {
            "environments": ALL,
            "productversion": ALL_WITH_RELATIONS,
            "case": ALL_WITH_RELATIONS,
            "tags": ALL_WITH_RELATIONS,
            }

class SuiteCaseSelectionResource(ModelResource):
    """
    Specialty end-point for an AJAX call in the Suite form multi-select widget
    for selecting cases.
    """

    case = fields.ForeignKey(CaseResource, "case")
    productversion = fields.ForeignKey(ProductVersionResource, "productversion")
    tags = fields.ToManyField(TagResource, "tags", full=True)

    class Meta:
        queryset = CaseVersion.objects.filter(latest=True).select_related(
            "case",
            "productversion",
            )
        # @@@ Django 1.4 - use prefetch_related on the tag field
        list_allowed_methods = ['get']
        fields = ["id", "name"]
        filtering = {
            "productversion": ALL_WITH_RELATIONS,
            }

    def get_list(self, request, **kwargs):
        """
        Save the suitecases orders so we don't have to query for each case.

        @@@ Django 1.4 - shouldn't need this when we have prefetch_related
        in Django 1.4
        """
        if "for_suite" in request.GET.keys():
             sc = SuiteCase.objects.filter(suite__id=request.GET["for_suite"])
             self.suitecases_cache = dict((x.case_id, x.order) for x in sc)
        return super(SuiteCaseSelectionResource, self).get_list(
            request, **kwargs)

    def dehydrate(self, bundle):
        """Add some convenience fields to the return JSON."""

        case = bundle.obj.case
        bundle.data["case_id"] = unicode(case.id)
        bundle.data["product_id"] = unicode(case.product_id)
        bundle.data["product"] = {"id": unicode(case.product_id)}

        try:
            bundle.data["created_by"] = {
                "id": unicode(case.created_by.id),
                "username": case.created_by.username,
                }
        except AttributeError:
            bundle.data["created_by"] = None

        try:
            bundle.data["order"] = self.suitecases_cache[case.id]
        except (KeyError, TypeError, AttributeError):
            # suitecases_cache may not be defined, or may be none
            # or may just not contain the id we're looking for.
            # either way, set it to None
            bundle.data["order"] = None

        return bundle

    def create_response(self, request, data, response_class=HttpResponse, **response_kwargs):
        """
        Remove the "cached" runsuites because we're done with it.

        @@@ Django 1.4 - shouldn't need this when we have prefetch_related
        in Django 1.4
        """
        self.suitecases_cache = None
        return super(SuiteCaseSelectionResource, self).create_response(
            request, data, response_class=HttpResponse, **response_kwargs)

    def alter_list_data_to_serialize(self, request, data):
        """Split list of cases between included and excluded from the suite"""
        included = [x for x in data["objects"] if x.data["order"] is not None]
        included = sorted(included, key=lambda k: k.data["order"])
        excluded =  [x for x in data["objects"] if x.data["order"] is None]
        data["objects"] = {"selected": included, "unselected": excluded}
        return data<|endoftext|>


<commit_before>import random
from mpmath import *
from mpmath.libmp import *

def test_basic_string():
    """
    Test basic string conversion
    """
    mp.dps = 15
    assert mpf('3') == mpf('3.0') == mpf('0003.') == mpf('0.03e2') == mpf(3.0)
    assert mpf('30') == mpf('30.0') == mpf('00030.') == mpf(30.0)
    for i in range(10):
        for j in range(10):
            assert mpf('%ie%i' % (i,j)) == i * 10**j
    assert str(mpf('25000.0')) == '25000.0'
    assert str(mpf('2500.0')) == '2500.0'
    assert str(mpf('250.0')) == '250.0'
    assert str(mpf('25.0')) == '25.0'
    assert str(mpf('2.5')) == '2.5'
    assert str(mpf('0.25')) == '0.25'
    assert str(mpf('0.025')) == '0.025'
    assert str(mpf('0.0025')) == '0.0025'
    assert str(mpf('0.00025')) == '0.00025'
    assert str(mpf('0.000025')) == '2.5e-5'
    assert str(mpf(0)) == '0.0'
    assert str(mpf('2.5e1000000000000000000000')) == '2.5e+1000000000000000000000'
    assert str(mpf('2.6e-1000000000000000000000')) == '2.6e-1000000000000000000000'
    assert str(mpf(1.23402834e-15)) == '1.23402834e-15'
    assert str(mpf(-1.23402834e-15)) == '-1.23402834e-15'
    assert str(mpf(-1.2344e-15)) == '-1.2344e-15'
    assert repr(mpf(-1.2344e-15)) == "mpf('-1.2343999999999999e-15')"
    assert str(mpf("2163048125L")) == '2163048125.0'
    assert str(mpf("-2163048125l")) == '-2163048125.0'
    assert str(mpf("-2163048125L/1088391168")) == '-1.98738118113799'
    assert str(mpf("2163048125/1088391168l")) == '1.98738118113799'

def test_pretty():
    mp.pretty = True
    assert repr(mpf(2.5)) == '2.5'
    assert repr(mpc(2.5,3.5)) == '(2.5 + 3.5j)'
    mp.pretty = False
    iv.pretty = True
    assert repr(mpi(2.5,3.5)) == '[2.5, 3.5]'
    iv.pretty = False

def test_str_whitespace():
    assert mpf('1.26 ') == 1.26

def test_unicode():
    mp.dps = 15
    try:
        unicode = unicode
    except NameError:
        unicode = str
    assert mpf(unicode('2.76')) == 2.76
    assert mpf(unicode('inf')) == inf

def test_str_format():
    assert to_str(from_float(0.1),15,strip_zeros=False) == '0.100000000000000'
    assert to_str(from_float(0.0),15,show_zero_exponent=True) == '0.0e+0'
    assert to_str(from_float(0.0),0,show_zero_exponent=True) == '.0e+0'
    assert to_str(from_float(0.0),0,show_zero_exponent=False) == '.0'
    assert to_str(from_float(0.0),1,show_zero_exponent=True) == '0.0e+0'
    assert to_str(from_float(0.0),1,show_zero_exponent=False) == '0.0'
    assert to_str(from_float(1.23),3,show_zero_exponent=True) == '1.23e+0'
    assert to_str(from_float(1.23456789000000e-2),15,strip_zeros=False,min_fixed=0,max_fixed=0) == '1.23456789000000e-2'
    assert to_str(from_float(1.23456789000000e+2),15,strip_zeros=False,min_fixed=0,max_fixed=0) == '1.23456789000000e+2'
    assert to_str(from_float(2.1287e14), 15, max_fixed=1000) == '212870000000000.0'
    assert to_str(from_float(2.1287e15), 15, max_fixed=1000) == '2128700000000000.0'
    assert to_str(from_float(2.1287e16), 15, max_fixed=1000) == '21287000000000000.0'
    assert to_str(from_float(2.1287e30), 15, max_fixed=1000) == '2128700000000000000000000000000.0'

def test_tight_string_conversion():
    mp.dps = 15
    # In an old version, '0.5' wasn't recognized as representing
    # an exact binary number and was erroneously rounded up or down
    assert from_str('0.5', 10, round_floor) == fhalf
    assert from_str('0.5', 10, round_ceiling) == fhalf

def test_eval_repr_invariant():
    """Test that eval(repr(x)) == x"""
    random.seed(123)
    for dps in [10, 15, 20, 50, 100]:
        mp.dps = dps
        for i in range(1000):
            a = mpf(random.random())**0.5 * 10**random.randint(-100, 100)
            assert eval(repr(a)) == a
    mp.dps = 15

def test_str_bugs():
    mp.dps = 15
    # Decimal rounding used to give the wrong exponent in some cases
    assert str(mpf('1e600')) == '1.0e+600'
    assert str(mpf('1e10000')) == '1.0e+10000'

def test_str_prec0():
    assert to_str(from_float(1.234), 0) == '.0e+0'
    assert to_str(from_float(1e-15), 0) == '.0e-15'
    assert to_str(from_float(1e+15), 0) == '.0e+15'
    assert to_str(from_float(-1e-15), 0) == '-.0e-15'
    assert to_str(from_float(-1e+15), 0) == '-.0e+15'

def test_convert_rational():
    mp.dps = 15
    assert from_rational(30, 5, 53, round_nearest) == (0, 3, 1, 2)
    assert from_rational(-7, 4, 53, round_nearest) == (1, 7, -2, 3)
    assert to_rational((0, 1, -1, 1)) == (1, 2)

def test_custom_class():
    class mympf:
        @property
        def _mpf_(self):
            return mpf(3.5)._mpf_
    class mympc:
        @property
        def _mpc_(self):
            return mpf(3.5)._mpf_, mpf(2.5)._mpf_
    assert mpf(2) + mympf() == 5.5
    assert mympf() + mpf(2) == 5.5
    assert mpf(mympf()) == 3.5
    assert mympc() + mpc(2) == mpc(5.5, 2.5)
    assert mpc(2) + mympc() == mpc(5.5, 2.5)
    assert mpc(mympc()) == (3.5+2.5j)

def test_conversion_methods():
    class SomethingRandom:
        pass
    class SomethingReal:
        def _mpmath_(self, prec, rounding):
            return mp.make_mpf(from_str('1.3', prec, rounding))
    class SomethingComplex:
        def _mpmath_(self, prec, rounding):
            return mp.make_mpc((from_str('1.3', prec, rounding), \
                from_str('1.7', prec, rounding)))
    x = mpf(3)
    z = mpc(3)
    a = SomethingRandom()
    y = SomethingReal()
    w = SomethingComplex()
    for d in [15, 45]:
        mp.dps = d
        assert (x+y).ae(mpf('4.3'))
        assert (y+x).ae(mpf('4.3'))
        assert (x+w).ae(mpc('4.3', '1.7'))
        assert (w+x).ae(mpc('4.3', '1.7'))
        assert (z+y).ae(mpc('4.3'))
        assert (y+z).ae(mpc('4.3'))
        assert (z+w).ae(mpc('4.3', '1.7'))
        assert (w+z).ae(mpc('4.3', '1.7'))
        x-y; y-x; x-w; w-x; z-y; y-z; z-w; w-z
        x*y; y*x; x*w; w*x; z*y; y*z; z*w; w*z
        x/y; y/x; x/w; w/x; z/y; y/z; z/w; w/z
        x**y; y**x; x**w; w**x; z**y; y**z; z**w; w**z
        x==y; y==x; x==w; w==x; z==y; y==z; z==w; w==z
    mp.dps = 15
    assert x.__add__(a) is NotImplemented
    assert x.__radd__(a) is NotImplemented
    assert x.__lt__(a) is NotImplemented
    assert x.__gt__(a) is NotImplemented
    assert x.__le__(a) is NotImplemented
    assert x.__ge__(a) is NotImplemented
    assert x.__eq__(a) is NotImplemented
    assert x.__ne__(a) is NotImplemented
    # implementation detail
    if hasattr(x, "__cmp__"):
        assert x.__cmp__(a) is NotImplemented
    assert x.__sub__(a) is NotImplemented
    assert x.__rsub__(a) is NotImplemented
    assert x.__mul__(a) is NotImplemented
    assert x.__rmul__(a) is NotImplemented
    assert x.__div__(a) is NotImplemented
    assert x.__rdiv__(a) is NotImplemented
    assert x.__mod__(a) is NotImplemented
    assert x.__rmod__(a) is NotImplemented
    assert x.__pow__(a) is NotImplemented
    assert x.__rpow__(a) is NotImplemented
    assert z.__add__(a) is NotImplemented
    assert z.__radd__(a) is NotImplemented
    assert z.__eq__(a) is NotImplemented
    assert z.__ne__(a) is NotImplemented
    assert z.__sub__(a) is NotImplemented
    assert z.__rsub__(a) is NotImplemented
    assert z.__mul__(a) is NotImplemented
    assert z.__rmul__(a) is NotImplemented
    assert z.__div__(a) is NotImplemented
    assert z.__rdiv__(a) is NotImplemented
    assert z.__pow__(a) is NotImplemented
    assert z.__rpow__(a) is NotImplemented

def test_mpmathify():
    assert mpmathify('1/2') == 0.5
    assert mpmathify('(1.0+1.0j)') == mpc(1, 1)
    assert mpmathify('(1.2e-10 - 3.4e5j)') == mpc('1.2e-10', '-3.4e5')
    assert mpmathify('1j') == mpc(1j)

def test_issue548():
    try:
        # This expression is invalid, but may trigger the ReDOS vulnerability
        # in the regular expression.
        mpmathify('(' + '1' * 5000 + '!j')
    except:
        return
    # The expression is invalid and should raise an exception.
    assert False

def test_compatibility():
    try:
        import numpy as np
        from fractions import Fraction
        from decimal import Decimal
        import decimal
    except ImportError:
        return
    # numpy types
    for nptype in np.core.numerictypes.typeDict.values():
        if issubclass(nptype, np.complexfloating):
            x = nptype(complex(0.5, -0.5))
        elif issubclass(nptype, np.floating):
            x = nptype(0.5)
        elif issubclass(nptype, np.integer):
            x = nptype(2)
        # Handle the weird types
        try: diff = np.abs(type(np.sqrt(x))(sqrt(x)) - np.sqrt(x))
        except: continue
        assert diff < 2.0**-53
    #Fraction and Decimal
    oldprec = mp.prec
    mp.prec = 1000
    decimal.getcontext().prec = mp.dps
    assert sqrt(Fraction(2, 3)).ae(sqrt(mpf('2/3')))
    assert sqrt(Decimal(2)/Decimal(3)).ae(sqrt(mpf('2/3')))
    mp.prec = oldprec
<commit_msg>Improve comment<commit_after>import random
from mpmath import *
from mpmath.libmp import *

def test_basic_string():
    """
    Test basic string conversion
    """
    mp.dps = 15
    assert mpf('3') == mpf('3.0') == mpf('0003.') == mpf('0.03e2') == mpf(3.0)
    assert mpf('30') == mpf('30.0') == mpf('00030.') == mpf(30.0)
    for i in range(10):
        for j in range(10):
            assert mpf('%ie%i' % (i,j)) == i * 10**j
    assert str(mpf('25000.0')) == '25000.0'
    assert str(mpf('2500.0')) == '2500.0'
    assert str(mpf('250.0')) == '250.0'
    assert str(mpf('25.0')) == '25.0'
    assert str(mpf('2.5')) == '2.5'
    assert str(mpf('0.25')) == '0.25'
    assert str(mpf('0.025')) == '0.025'
    assert str(mpf('0.0025')) == '0.0025'
    assert str(mpf('0.00025')) == '0.00025'
    assert str(mpf('0.000025')) == '2.5e-5'
    assert str(mpf(0)) == '0.0'
    assert str(mpf('2.5e1000000000000000000000')) == '2.5e+1000000000000000000000'
    assert str(mpf('2.6e-1000000000000000000000')) == '2.6e-1000000000000000000000'
    assert str(mpf(1.23402834e-15)) == '1.23402834e-15'
    assert str(mpf(-1.23402834e-15)) == '-1.23402834e-15'
    assert str(mpf(-1.2344e-15)) == '-1.2344e-15'
    assert repr(mpf(-1.2344e-15)) == "mpf('-1.2343999999999999e-15')"
    assert str(mpf("2163048125L")) == '2163048125.0'
    assert str(mpf("-2163048125l")) == '-2163048125.0'
    assert str(mpf("-2163048125L/1088391168")) == '-1.98738118113799'
    assert str(mpf("2163048125/1088391168l")) == '1.98738118113799'

def test_pretty():
    mp.pretty = True
    assert repr(mpf(2.5)) == '2.5'
    assert repr(mpc(2.5,3.5)) == '(2.5 + 3.5j)'
    mp.pretty = False
    iv.pretty = True
    assert repr(mpi(2.5,3.5)) == '[2.5, 3.5]'
    iv.pretty = False

def test_str_whitespace():
    assert mpf('1.26 ') == 1.26

def test_unicode():
    mp.dps = 15
    try:
        unicode = unicode
    except NameError:
        unicode = str
    assert mpf(unicode('2.76')) == 2.76
    assert mpf(unicode('inf')) == inf

def test_str_format():
    assert to_str(from_float(0.1),15,strip_zeros=False) == '0.100000000000000'
    assert to_str(from_float(0.0),15,show_zero_exponent=True) == '0.0e+0'
    assert to_str(from_float(0.0),0,show_zero_exponent=True) == '.0e+0'
    assert to_str(from_float(0.0),0,show_zero_exponent=False) == '.0'
    assert to_str(from_float(0.0),1,show_zero_exponent=True) == '0.0e+0'
    assert to_str(from_float(0.0),1,show_zero_exponent=False) == '0.0'
    assert to_str(from_float(1.23),3,show_zero_exponent=True) == '1.23e+0'
    assert to_str(from_float(1.23456789000000e-2),15,strip_zeros=False,min_fixed=0,max_fixed=0) == '1.23456789000000e-2'
    assert to_str(from_float(1.23456789000000e+2),15,strip_zeros=False,min_fixed=0,max_fixed=0) == '1.23456789000000e+2'
    assert to_str(from_float(2.1287e14), 15, max_fixed=1000) == '212870000000000.0'
    assert to_str(from_float(2.1287e15), 15, max_fixed=1000) == '2128700000000000.0'
    assert to_str(from_float(2.1287e16), 15, max_fixed=1000) == '21287000000000000.0'
    assert to_str(from_float(2.1287e30), 15, max_fixed=1000) == '2128700000000000000000000000000.0'

def test_tight_string_conversion():
    mp.dps = 15
    # In an old version, '0.5' wasn't recognized as representing
    # an exact binary number and was erroneously rounded up or down
    assert from_str('0.5', 10, round_floor) == fhalf
    assert from_str('0.5', 10, round_ceiling) == fhalf

def test_eval_repr_invariant():
    """Test that eval(repr(x)) == x"""
    random.seed(123)
    for dps in [10, 15, 20, 50, 100]:
        mp.dps = dps
        for i in range(1000):
            a = mpf(random.random())**0.5 * 10**random.randint(-100, 100)
            assert eval(repr(a)) == a
    mp.dps = 15

def test_str_bugs():
    mp.dps = 15
    # Decimal rounding used to give the wrong exponent in some cases
    assert str(mpf('1e600')) == '1.0e+600'
    assert str(mpf('1e10000')) == '1.0e+10000'

def test_str_prec0():
    assert to_str(from_float(1.234), 0) == '.0e+0'
    assert to_str(from_float(1e-15), 0) == '.0e-15'
    assert to_str(from_float(1e+15), 0) == '.0e+15'
    assert to_str(from_float(-1e-15), 0) == '-.0e-15'
    assert to_str(from_float(-1e+15), 0) == '-.0e+15'

def test_convert_rational():
    mp.dps = 15
    assert from_rational(30, 5, 53, round_nearest) == (0, 3, 1, 2)
    assert from_rational(-7, 4, 53, round_nearest) == (1, 7, -2, 3)
    assert to_rational((0, 1, -1, 1)) == (1, 2)

def test_custom_class():
    class mympf:
        @property
        def _mpf_(self):
            return mpf(3.5)._mpf_
    class mympc:
        @property
        def _mpc_(self):
            return mpf(3.5)._mpf_, mpf(2.5)._mpf_
    assert mpf(2) + mympf() == 5.5
    assert mympf() + mpf(2) == 5.5
    assert mpf(mympf()) == 3.5
    assert mympc() + mpc(2) == mpc(5.5, 2.5)
    assert mpc(2) + mympc() == mpc(5.5, 2.5)
    assert mpc(mympc()) == (3.5+2.5j)

def test_conversion_methods():
    class SomethingRandom:
        pass
    class SomethingReal:
        def _mpmath_(self, prec, rounding):
            return mp.make_mpf(from_str('1.3', prec, rounding))
    class SomethingComplex:
        def _mpmath_(self, prec, rounding):
            return mp.make_mpc((from_str('1.3', prec, rounding), \
                from_str('1.7', prec, rounding)))
    x = mpf(3)
    z = mpc(3)
    a = SomethingRandom()
    y = SomethingReal()
    w = SomethingComplex()
    for d in [15, 45]:
        mp.dps = d
        assert (x+y).ae(mpf('4.3'))
        assert (y+x).ae(mpf('4.3'))
        assert (x+w).ae(mpc('4.3', '1.7'))
        assert (w+x).ae(mpc('4.3', '1.7'))
        assert (z+y).ae(mpc('4.3'))
        assert (y+z).ae(mpc('4.3'))
        assert (z+w).ae(mpc('4.3', '1.7'))
        assert (w+z).ae(mpc('4.3', '1.7'))
        x-y; y-x; x-w; w-x; z-y; y-z; z-w; w-z
        x*y; y*x; x*w; w*x; z*y; y*z; z*w; w*z
        x/y; y/x; x/w; w/x; z/y; y/z; z/w; w/z
        x**y; y**x; x**w; w**x; z**y; y**z; z**w; w**z
        x==y; y==x; x==w; w==x; z==y; y==z; z==w; w==z
    mp.dps = 15
    assert x.__add__(a) is NotImplemented
    assert x.__radd__(a) is NotImplemented
    assert x.__lt__(a) is NotImplemented
    assert x.__gt__(a) is NotImplemented
    assert x.__le__(a) is NotImplemented
    assert x.__ge__(a) is NotImplemented
    assert x.__eq__(a) is NotImplemented
    assert x.__ne__(a) is NotImplemented
    # implementation detail
    if hasattr(x, "__cmp__"):
        assert x.__cmp__(a) is NotImplemented
    assert x.__sub__(a) is NotImplemented
    assert x.__rsub__(a) is NotImplemented
    assert x.__mul__(a) is NotImplemented
    assert x.__rmul__(a) is NotImplemented
    assert x.__div__(a) is NotImplemented
    assert x.__rdiv__(a) is NotImplemented
    assert x.__mod__(a) is NotImplemented
    assert x.__rmod__(a) is NotImplemented
    assert x.__pow__(a) is NotImplemented
    assert x.__rpow__(a) is NotImplemented
    assert z.__add__(a) is NotImplemented
    assert z.__radd__(a) is NotImplemented
    assert z.__eq__(a) is NotImplemented
    assert z.__ne__(a) is NotImplemented
    assert z.__sub__(a) is NotImplemented
    assert z.__rsub__(a) is NotImplemented
    assert z.__mul__(a) is NotImplemented
    assert z.__rmul__(a) is NotImplemented
    assert z.__div__(a) is NotImplemented
    assert z.__rdiv__(a) is NotImplemented
    assert z.__pow__(a) is NotImplemented
    assert z.__rpow__(a) is NotImplemented

def test_mpmathify():
    assert mpmathify('1/2') == 0.5
    assert mpmathify('(1.0+1.0j)') == mpc(1, 1)
    assert mpmathify('(1.2e-10 - 3.4e5j)') == mpc('1.2e-10', '-3.4e5')
    assert mpmathify('1j') == mpc(1j)

def test_issue548():
    try:
        # This expression is invalid, but may trigger the ReDOS vulnerability
        # in the regular expression for parsing complex numbers.
        mpmathify('(' + '1' * 5000 + '!j')
    except:
        return
    # The expression is invalid and should raise an exception.
    assert False

def test_compatibility():
    try:
        import numpy as np
        from fractions import Fraction
        from decimal import Decimal
        import decimal
    except ImportError:
        return
    # numpy types
    for nptype in np.core.numerictypes.typeDict.values():
        if issubclass(nptype, np.complexfloating):
            x = nptype(complex(0.5, -0.5))
        elif issubclass(nptype, np.floating):
            x = nptype(0.5)
        elif issubclass(nptype, np.integer):
            x = nptype(2)
        # Handle the weird types
        try: diff = np.abs(type(np.sqrt(x))(sqrt(x)) - np.sqrt(x))
        except: continue
        assert diff < 2.0**-53
    #Fraction and Decimal
    oldprec = mp.prec
    mp.prec = 1000
    decimal.getcontext().prec = mp.dps
    assert sqrt(Fraction(2, 3)).ae(sqrt(mpf('2/3')))
    assert sqrt(Decimal(2)/Decimal(3)).ae(sqrt(mpf('2/3')))
    mp.prec = oldprec
<|endoftext|>


<commit_before>import django_rq
import os
import requests
import time
from django.core.cache import cache
from mrbelvedereci.cumulusci.models import Org
from mrbelvedereci.repository.utils import create_status
from mrbelvedereci.build.signals import build_complete

BUILD_TIMEOUT=28800

@django_rq.job('default', timeout=BUILD_TIMEOUT)
def run_build(build_id, lock_id=None):
    from mrbelvedereci.build.models import Build
    try:
        build = Build.objects.get(id=build_id)
        exception = None
        build.run()
        res_status = set_github_status.delay(build_id)
        build.task_id_status_end = res_status.id
        build.save()

        build_complete.send(sender=build.__class__, build=build, status=build.status)

    except Exception as e:
        if lock_id:
            cache.delete(lock_id)

        res_status = set_github_status.delay(build_id)
        build.task_id_status_end = res_status.id
        build.status = 'error'
        build.log += '\nERROR: The build raised an exception\n'
        build.log += unicode(e)
        build.save()

        build_complete.send(sender=build.__class__, build=build, status=build.status)

    if lock_id:
        cache.delete(lock_id)

    # Restart the Heroku dyno if on Heroku
    dyno_id = os.environ.get('HEROKU_DYNO_ID')
    api_token = os.environ.get('HEROKU_API_TOKEN')
    app_id = os.environ.get('HEROKU_APP_ID')
    if dyno_id and api_token and app_id:
        headers = {
            'Accept': "application/vnd.heroku+json; version=3",
            "Authorization": "Bearer {}".format(api_token),
        }
        resp = requests.delete('https://api.heroku.com/apps/{}/dynos/{}'.format(app_id, dyno_id), headers=headers)

    return build.status

@django_rq.job('short', timeout=60)
def check_queued_build(build_id):
    from mrbelvedereci.build.models import Build
    try:
        build = Build.objects.get(id = build_id)
    except Build.DoesNotExist:
        time.sleep(1)
        check_queued_build.delay(build_id)

    # Check for concurrency blocking
    try:
        org = Org.objects.get(name = build.plan.org, repo = build.repo)
    except Org.DoesNotExist:
        return

    if org.scratch:
        # For scratch orgs, we don't need concurrency blocking logic, just run the build
        res_run = run_build.delay(build.id)
        build.task_id_run = res_run.id
        build.save()
        return "Org is a scratch org, running build concurrently as task {}".format(res_run.id)

    else:
        # For persistent orgs, use the cache to lock the org
        lock_id = 'mrbelvedereci-org-lock-{}'.format(org.id)
        status = cache.add(lock_id, 'build-{}'.format(build_id), timeout=BUILD_TIMEOUT)

        if status is True:
            # Lock successful, run the build
            res_run = run_build.delay(build.id, lock_id)
            build.task_id_run = res_run.id
            build.save()
            return "Got a lock on the org, running as task {}".format(res_run.id)
        else:
            # Failed to get lock, queue next check
            return "Failed to get lock on org.  {} has the org locked.  Queueing next check.".format(cache.get(lock_id))

@django_rq.job('short', timeout=60)
def check_queued_builds():
    from mrbelvedereci.build.models import Build
    builds = []
    for build in Build.objects.filter(status = 'queued').order_by('time_queue'):
        builds.append(build.id)
        check_queued_build.delay(build.id)

    if builds:
        return 'Checked queued builds: {}'.format(', '.join(builds))
    else:
        return 'No queued builds to check'

@django_rq.job('short')
def set_github_status(build_id):
    from mrbelvedereci.build.models import Build
    build = Build.objects.get(id = build_id)
    create_status(build)

@django_rq.job('short')
def check_build_tasks():
    from mrbelvedereci.build.models import Build
    builds = Build.objects.filter(status = 'running')
    for build in builds:
        task_id = build.task_id_run

@django_rq.job('short')
def delete_scratch_orgs():
    from mrbelvedereci.cumulusci.models import ScratchOrgInstance
    orgs_deleted = 0
    orgs_failed = 0
    for org in ScratchOrgInstance.objects.filter(delete_error__isnull = False):
        org.delete_org()
        if org.deleted:
            orgs_deleted += 1
        else:
            orgs_failed += 1

    if orgs_deleted and not orgs_failed:
        return 'No orgs found to delete'

    return 'Deleted {} orgs and failed to delete {} orgs'.format(orgs_deleted, orgs_failed)
<commit_msg>Reset the django database connection at the start of all RQ jobs<commit_after>import django_rq
import os
import requests
import time
from django.core.cache import cache
from mrbelvedereci.cumulusci.models import Org
from mrbelvedereci.repository.utils import create_status
from mrbelvedereci.build.signals import build_complete

BUILD_TIMEOUT=28800

def reset_database_connection():
    from django import db
    db.close_connection()

@django_rq.job('default', timeout=BUILD_TIMEOUT)
def run_build(build_id, lock_id=None):
    reset_database_connection()
    from mrbelvedereci.build.models import Build
    try:
        build = Build.objects.get(id=build_id)
        exception = None
        build.run()
        res_status = set_github_status.delay(build_id)
        build.task_id_status_end = res_status.id
        build.save()

        build_complete.send(sender=build.__class__, build=build, status=build.status)

    except Exception as e:
        if lock_id:
            cache.delete(lock_id)

        res_status = set_github_status.delay(build_id)
        build.task_id_status_end = res_status.id
        build.status = 'error'
        build.log += '\nERROR: The build raised an exception\n'
        build.log += unicode(e)
        build.save()

        build_complete.send(sender=build.__class__, build=build, status=build.status)

    if lock_id:
        cache.delete(lock_id)

    # Restart the Heroku dyno if on Heroku
    dyno_id = os.environ.get('HEROKU_DYNO_ID')
    api_token = os.environ.get('HEROKU_API_TOKEN')
    app_id = os.environ.get('HEROKU_APP_ID')
    if dyno_id and api_token and app_id:
        headers = {
            'Accept': "application/vnd.heroku+json; version=3",
            "Authorization": "Bearer {}".format(api_token),
        }
        resp = requests.delete('https://api.heroku.com/apps/{}/dynos/{}'.format(app_id, dyno_id), headers=headers)

    return build.status

@django_rq.job('short', timeout=60)
def check_queued_build(build_id):
    reset_database_connection()

    from mrbelvedereci.build.models import Build
    try:
        build = Build.objects.get(id = build_id)
    except Build.DoesNotExist:
        time.sleep(1)
        check_queued_build.delay(build_id)

    # Check for concurrency blocking
    try:
        org = Org.objects.get(name = build.plan.org, repo = build.repo)
    except Org.DoesNotExist:
        return

    if org.scratch:
        # For scratch orgs, we don't need concurrency blocking logic, just run the build
        res_run = run_build.delay(build.id)
        build.task_id_run = res_run.id
        build.save()
        return "Org is a scratch org, running build concurrently as task {}".format(res_run.id)

    else:
        # For persistent orgs, use the cache to lock the org
        lock_id = 'mrbelvedereci-org-lock-{}'.format(org.id)
        status = cache.add(lock_id, 'build-{}'.format(build_id), timeout=BUILD_TIMEOUT)

        if status is True:
            # Lock successful, run the build
            res_run = run_build.delay(build.id, lock_id)
            build.task_id_run = res_run.id
            build.save()
            return "Got a lock on the org, running as task {}".format(res_run.id)
        else:
            # Failed to get lock, queue next check
            return "Failed to get lock on org.  {} has the org locked.  Queueing next check.".format(cache.get(lock_id))

@django_rq.job('short', timeout=60)
def check_queued_builds():
    reset_database_connection()

    from mrbelvedereci.build.models import Build
    builds = []
    for build in Build.objects.filter(status = 'queued').order_by('time_queue'):
        builds.append(build.id)
        check_queued_build.delay(build.id)

    if builds:
        return 'Checked queued builds: {}'.format(', '.join(builds))
    else:
        return 'No queued builds to check'

@django_rq.job('short')
def set_github_status(build_id):
    reset_database_connection()

    from mrbelvedereci.build.models import Build
    build = Build.objects.get(id = build_id)
    create_status(build)

@django_rq.job('short')
def delete_scratch_orgs():
    reset_database_connection()

    from mrbelvedereci.cumulusci.models import ScratchOrgInstance
    orgs_deleted = 0
    orgs_failed = 0
    for org in ScratchOrgInstance.objects.filter(delete_error__isnull = False):
        org.delete_org()
        if org.deleted:
            orgs_deleted += 1
        else:
            orgs_failed += 1

    if orgs_deleted and not orgs_failed:
        return 'No orgs found to delete'

    return 'Deleted {} orgs and failed to delete {} orgs'.format(orgs_deleted, orgs_failed)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# © <2016> Cesar barron
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from openerp import _, api, fields, models
from openerp.exceptions import UserError

class MrpBom(models.Model):
    _name = "mrp.bom"
    _inherit = "mrp.bom"

    warehouse_id = fields.Many2one(
        'stock.warehouse',
        string=_('Warehouse'),
        required=True)

    @api.multi
    def write(self, values):
        # te traes el producto anterior
        # val = self.product_tmpl_id
        if 'type' in values.keys():
            types = values['type']
        else:
            types = self.type
        if 'warehouse_id' in values.keys():
            ware_obj = self.env['stock.warehouse']
            ware = ware_obj.browse(values['warehouse_id'])
        else:
            ware = self.warehouse_id
        if 'routing_id' in values.keys():
            routing_obj = self.env['mrp.routing']
            routing = routing_obj.browse(values['routing_id'])
        else:
            routing = self.routing_id
        if types == 'normal':
            if ware.id != routing.location_id.stock_warehouse_id.id:
                raise UserError(_('The production route must'
                                  ' be in the same warehouse than the bom'))
        if types == 'phantom':
            if routing.id != 0:
                raise UserError(_('Kit products should not have route production'))

        if 'product_tmpl_id' in values.keys():
            # te traes el objeto vacio
            template = self.env['product.template']
            # se construye el objeto, y los busca por medio del values
            val = template.browse(values['product_tmpl_id'])
            # condicion para la busquedan
            for route in val.route_ids:
                # Se le agrega el id como busqueda, cambia bd cambiarlo
                if route.id == 6:
                    raise UserError(_('This product is raw material'))
        else:
            val = self.product_tmpl_id

        if 'product_id' in values.keys():
            producto_obj = self.env['product.product']
            product = producto_obj.browse(values['product_id'])

        else:
            product = self.product_id

        if val.id != product.product_tmpl_id.id:
            raise UserError(_('Product and template it does not match'))
        return super(MrpBom, self).write(values)

    @api.model
    def create(self, vals):
        # objeto para no guardar variantes ya existentes
        # bom_obj = self.env['mrp.bom']
        ware_obj = self.env['stock.warehouse']
        routing_obj = self.env['mrp.routing']
        producto_obj = self.env['product.product']
        template = self.env['product.template']
        val = template.browse(vals['product_tmpl_id'])
        ware = ware_obj.browse(vals['warehouse_id'])
        routing = routing_obj.browse(vals['routing_id'])
        if 'product_id' in vals.keys():
            product = producto_obj.browse(vals['product_id'])
            if val.id != product.product_tmpl_id.id:
                raise UserError(_('Product and template it does not match'))
        # objeto de busqueda para ver si ya existe
        # bom_id = bom_obj.search([('product_id', "=", vals['product_id']),
        #                         ('active', '=', True)])
        # if len(bom_id) > 0:
        #    raise UserError(_('This product is already exists'))
        if vals['type'] == 'normal':
            if ware.id != routing.location_id.stock_warehouse_id.id:
                raise UserError(_('The production route must'
                                  'be in the same warehouse than the bom'))
        if vals['type'] == 'phantom':
            if routing.id != 0:
                raise UserError(_('Kit products should not have route production'))
        for route in val.route_ids:
            if route.id == 6:
                raise UserError(_('This product is raw material'))

        return super(MrpBom, self).create(vals)

class MrpBomLine(models.Model):
    _name = "mrp.bom.line"
    _inherit = "mrp.bom.line"

    location_id = fields.Many2one(
        'stock.location',
        string=_('Location'),
        required=True)

    @api.model
    def create(self, values):
        bom_obj = self.env['mrp.bom']
        product_obj = self.env['product.product']
        if 'bom_id' in values.keys():
            bom = bom_obj.browse([values['bom_id']])
            product = product_obj.browse([values['product_id']])
            if bom.type == 'phantom':
                product_bom = bom_obj.search([
                    ('product_id', '=', values['product_id'])])
                if not product_bom:
                    raise UserError(_('You can not add a product that \
                        has no BOM: %s') % (product.name,))
            if product.standard_price == 0:
                raise UserError(_('You can not add a product with cost 0: %s')
                                % (product.name,))
        return super(MrpBomLine, self).create(values)
<commit_msg>Comentariada validacion de costo cero mientras subimos el resto de los detalles<commit_after># -*- coding: utf-8 -*-
# © <2016> Cesar barron
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from openerp import _, api, fields, models
from openerp.exceptions import UserError

class MrpBom(models.Model):
    _name = "mrp.bom"
    _inherit = "mrp.bom"

    warehouse_id = fields.Many2one(
        'stock.warehouse',
        string=_('Warehouse'),
        required=True)

    @api.multi
    def write(self, values):
        # te traes el producto anterior
        # val = self.product_tmpl_id
        if 'type' in values.keys():
            types = values['type']
        else:
            types = self.type
        if 'warehouse_id' in values.keys():
            ware_obj = self.env['stock.warehouse']
            ware = ware_obj.browse(values['warehouse_id'])
        else:
            ware = self.warehouse_id
        if 'routing_id' in values.keys():
            routing_obj = self.env['mrp.routing']
            routing = routing_obj.browse(values['routing_id'])
        else:
            routing = self.routing_id
        if types == 'normal':
            if ware.id != routing.location_id.stock_warehouse_id.id:
                raise UserError(_('The production route must'
                                  ' be in the same warehouse than the bom'))
        if types == 'phantom':
            if routing.id != 0:
                raise UserError(_('Kit products should not have route production'))

        if 'product_tmpl_id' in values.keys():
            # te traes el objeto vacio
            template = self.env['product.template']
            # se construye el objeto, y los busca por medio del values
            val = template.browse(values['product_tmpl_id'])
            # condicion para la busquedan
            for route in val.route_ids:
                # Se le agrega el id como busqueda, cambia bd cambiarlo
                if route.id == 6:
                    raise UserError(_('This product is raw material'))
        else:
            val = self.product_tmpl_id

        if 'product_id' in values.keys():
            producto_obj = self.env['product.product']
            product = producto_obj.browse(values['product_id'])

        else:
            product = self.product_id

        if val.id != product.product_tmpl_id.id:
            raise UserError(_('Product and template it does not match'))
        return super(MrpBom, self).write(values)

    @api.model
    def create(self, vals):
        # objeto para no guardar variantes ya existentes
        # bom_obj = self.env['mrp.bom']
        ware_obj = self.env['stock.warehouse']
        routing_obj = self.env['mrp.routing']
        producto_obj = self.env['product.product']
        template = self.env['product.template']
        val = template.browse(vals['product_tmpl_id'])
        ware = ware_obj.browse(vals['warehouse_id'])
        routing = routing_obj.browse(vals['routing_id'])
        if 'product_id' in vals.keys():
            product = producto_obj.browse(vals['product_id'])
            if val.id != product.product_tmpl_id.id:
                raise UserError(_('Product and template it does not match'))
        # objeto de busqueda para ver si ya existe
        # bom_id = bom_obj.search([('product_id', "=", vals['product_id']),
        #                         ('active', '=', True)])
        # if len(bom_id) > 0:
        #    raise UserError(_('This product is already exists'))
        if vals['type'] == 'normal':
            if ware.id != routing.location_id.stock_warehouse_id.id:
                raise UserError(_('The production route must'
                                  'be in the same warehouse than the bom'))
        if vals['type'] == 'phantom':
            if routing.id != 0:
                raise UserError(_('Kit products should not have route production'))
        for route in val.route_ids:
            if route.id == 6:
                raise UserError(_('This product is raw material'))

        return super(MrpBom, self).create(vals)

class MrpBomLine(models.Model):
    _name = "mrp.bom.line"
    _inherit = "mrp.bom.line"

    location_id = fields.Many2one(
        'stock.location',
        string=_('Location'),
        required=True)

    @api.model
    def create(self, values):
        bom_obj = self.env['mrp.bom']
        product_obj = self.env['product.product']
        if 'bom_id' in values.keys():
            bom = bom_obj.browse([values['bom_id']])
            product = product_obj.browse([values['product_id']])
            if bom.type == 'phantom':
                product_bom = bom_obj.search([
                    ('product_id', '=', values['product_id'])])
                if not product_bom:
                    raise UserError(_('You can not add a product that \
                        has no BOM: %s') % (product.name,))
            # Comentariado temporalmente para subir detalles restantes
            #if product.standard_price == 0:
            #    raise UserError(_('You can not add a product with cost 0: %s')
            #                    % (product.name,))
        return super(MrpBomLine, self).create(values)
<|endoftext|>


<commit_before>import os
from cclib.parser import G03

t = G03(os.path.join("..","data","Gaussian","dvb_gopt.out"))
t.parse()

for x in ['scftargets','geotargets','scfvalues','geovalues']:
    print x
    t.__getattribute__(x)+1

<commit_msg>This test is included in the new ones instead<commit_after><|endoftext|>


<commit_before># Copyright 2017-2018 TensorHub, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os
import textwrap

import click

from guild import op_util
from guild import plugin as pluginlib

log = logging.getLogger("guild")

class ConsoleFormatter(click.HelpFormatter):

    _in_section = False

    def start_section(self, val):
        if self._in_section:
            self.dedent()
            self.dedent()
            self.write_paragraph()
        self.write_text(click.style(val, bold=True))
        self.write_paragraph()
        self.indent()
        self.indent()
        self._in_section = True

    def write_heading(self, heading):
        self.write_text(click.style(heading, bold=True))

    def write_subheading(self, val):
        self.write_text("%s:" % val)

    def write_description(self, val):
        for i, par in enumerate(val.split("\n")):
            if i > 0:
                self.write_paragraph()
            self.write_text(par)

class RestFormatter(click.HelpFormatter):

    _in_section = False
    _heading_chars = "#=^-`"
    _indent_level = 0

    def start_section(self, val):
        if self._in_section:
            self.write_paragraph()
        self.write_text(val)
        self.write_text(self._heading_char() * len(val))
        self.write_paragraph()
        self._in_section = True

    def _heading_char(self):
        assert self._indent_level < len(self._heading_chars)
        return self._heading_chars[self._indent_level]

    def write_heading(self, heading):
        self.write_text(heading)
        self.write_text(self._heading_char() * len(heading))

    def write_subheading(self, val):
        self.write_heading(val)

    def write_description(self, val):
        for i, par in enumerate(val.split("\n")):
            if i == 0:
                self.write_text("*%s*" % par)
            else:
                self.write_paragraph()
                self.write_text(par)

    def write_dl(self, rows, col_max=None, col_spacing=None,
                 preserve_paragraphs=False):
        for i, (name, desc) in enumerate(rows):
            if i > 0:
                self.write_paragraph()
            self.write_text("**%s**" % name)
            super(RestFormatter, self).indent()
            self.write_text("*%s*" % desc)
            super(RestFormatter, self).dedent()

    def indent(self):
        self._indent_level += 1

    def dedent(self):
        self._indent_level -= 1

def guildfile_console_help(guildfile, model_desc=None):
    out = ConsoleFormatter()
    out.start_section("OVERVIEW")
    _write_console_help_overview(guildfile, model_desc, out)
    out.start_section("MODELS")
    _write_models(guildfile, out)
    return "".join(out.buffer)

def _write_console_help_overview(guildfile, model_desc, out):
    model_desc = model_desc or _format_guildfile_dir(guildfile)
    out.write_text(textwrap.dedent(
        """
        You are viewing help for models defined in %s.

        To run a model operation use 'guild run MODEL:OPERATION' where
        MODEL is one of the model names listed below and OPERATION is
        an associated operation.

        You may set operation flags using 'FLAG=VALUE' arguments to
        the run command. Refer to the operations below for a list of
        supported flags. Model flags apply to all operations.

        For more help, try 'guild run --help' or 'guild --help'.
        """
        % model_desc))

def _format_guildfile_dir(mf):
    if _is_cwd(mf.dir):
        return "the current directory"
    else:
        relpath = os.path.relpath(mf.dir)
        if relpath[0] != '.':
            relpath = os.path.join(".", relpath)
        return "'%s'" % relpath

def _is_cwd(path):
    return os.path.abspath(path) == os.path.abspath(os.getcwd())

def package_description(guildfile):
    if not guildfile.models:
        return ""
    out = RestFormatter()
    out.start_section("Models")
    _write_models(guildfile, out)
    return "".join(out.buffer)

def _write_models(guildfile, out):
    i = 0
    for _name, model in sorted(guildfile.models.items()):
        if i > 0:
            out.write_paragraph()
        _write_model(model, out)
        i += 1

def _write_model(m, out):
    out.write_heading(m.name)
    out.indent()
    if m.description:
        out.write_paragraph()
        out.write_description(m.description)
    out.write_paragraph()
    _write_operations(m, out)
    out.write_paragraph()
    if m.references:
        _write_references(m.references, out)
    out.dedent()

def _write_operations(m, out):
    out.write_subheading("Operations")
    out.write_paragraph()
    out.indent()
    if m.operations:
        for i, op in enumerate(m.operations):
            if i > 0:
                out.write_paragraph()
            _write_operation(op, out)
    else:
        out.write_text(
            "No operations defined for this model")
    out.dedent()

def _write_operation(op, out):
    op = _maybe_apply_plugin_op(op)
    out.write_heading(op.name)
    out.indent()
    if op.description:
        out.write_paragraph()
        out.write_description(op.description)
    if op.flags:
        if op.description:
            out.write_paragraph()
        _write_flags(op.flags, "Flags", out)
    out.dedent()

def _maybe_apply_plugin_op(op):
    if op.plugin_op:
        for _name, plugin in pluginlib.iter_plugins():
            plugin_op = plugin.get_operation(op.plugin_op, op.modeldef, op)
            if plugin_op:
                return plugin_op
        log.warning(
            "Cannot find plugin op '%s' references in %s:%s",
            op.plugin_op, op.modeldef.name, op.name)
    return op

def _maybe_plugin_opdef(name, model, parent_opdef=None):
    for _name, plugin in pluginlib.iter_plugins():
        opdef = plugin.get_operation(name, model, parent_opdef)
        if opdef:
            return opdef
    return None

def _plugin_opdef(name, model, parent_opdef):
    opdef = _maybe_plugin_opdef(name, model, parent_opdef)
    if opdef is None:
        log.warning(
            "plugin-op '%s' specified by %s is not defined",
            parent_opdef.plugin_op.name, parent_opdef.fullname)
    return opdef

def _write_flags(flags, heading, out, no_flags_msg=None):
    out.write_subheading(heading)
    out.write_paragraph()
    out.indent()
    if flags:
        out.write_dl(flags_dl(flags), preserve_paragraphs=True)
    else:
        if no_flags_msg:
            out.write_description(no_flags_msg)
    out.dedent()

def flags_dl(flags):
    if not flags:
        return []
    max_flag_len = max([len(flag.name) for flag in flags])
    return [
        (flag.name, _format_flag_desc(flag, max_flag_len))
        for flag in flags
    ]

def _format_flag_desc(flag, max_flag_len):
    lines = flag.description.split("\n")
    if flag.default is not None:
        line1_suffix = " (%s)" % _default_label(flag.default)
    elif flag.required:
        line1_suffix = " (required)"
    elif flag.null_label:
        line1_suffix = " (%s)" % flag.null_label
    else:
        line1_suffix = ""
    lines[0] += line1_suffix
    if flag.choices:
        lines.append(_format_flag_choices(flag.choices, max_flag_len))
    if len(lines) > 1:
        return "\n\n".join(lines) + "\n\b\n"
    else:
        return lines[0]

def _default_label(val):
    return op_util.format_arg_value(val)

def _format_flag_choices(choices, max_flag_len):
    out = click.HelpFormatter()
    out.width = out.width - max_flag_len - 4
    out.write_heading("Choices")
    out.indent()
    out.write_dl(
        [(op_util.format_arg_value(choice.value),
          "\n\n".join(choice.description.split("\n")))
         for choice in choices],
        preserve_paragraphs=True)
    return "\n\b\n" + out.getvalue()

def _write_references(refs, out):
    out.write_subheading("References")
    out.write_paragraph()
    out.indent()
    for ref in refs:
        out.write_text("\b\n- %s" % ref)
    out.dedent()
<commit_msg>Cleanup generated package help<commit_after># Copyright 2017-2018 TensorHub, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os
import textwrap

import click

from guild import op_util
from guild import plugin as pluginlib

log = logging.getLogger("guild")

class ConsoleFormatter(click.HelpFormatter):

    _in_section = False

    def start_section(self, val):
        if self._in_section:
            self.dedent()
            self.dedent()
            self.write_paragraph()
        self.write_text(click.style(val, bold=True))
        self.write_paragraph()
        self.indent()
        self.indent()
        self._in_section = True

    def write_heading(self, heading):
        self.write_text(click.style(heading, bold=True))

    def write_subheading(self, val):
        self.write_text("%s:" % val)

    def write_description(self, val):
        for i, par in enumerate(val.split("\n")):
            if i > 0:
                self.write_paragraph()
            self.write_text(par)

class RestFormatter(click.HelpFormatter):

    _in_section = False
    _heading_chars = "#=^-`"
    _indent_level = 0

    def start_section(self, val):
        if self._in_section:
            self.dedent()
            self.write_paragraph()
        self.write_text(val)
        self.write_text(self._heading_char() * len(val))
        self.write_paragraph()
        self.indent()
        self._in_section = True

    def _heading_char(self):
        assert self._indent_level < len(self._heading_chars)
        return self._heading_chars[self._indent_level]

    def write_heading(self, heading):
        self.write_text(heading)
        self.write_text(self._heading_char() * len(heading))

    def write_subheading(self, val):
        self.write_heading(val)

    def write_description(self, val):
        for i, par in enumerate(val.split("\n")):
            if i == 0:
                self.write_text("*%s*" % par)
            else:
                self.write_paragraph()
                self.write_text(par)

    def write_dl(self, rows, col_max=None, col_spacing=None,
                 preserve_paragraphs=False):
        for i, (name, desc) in enumerate(rows):
            if i > 0:
                self.write_paragraph()
            self.write_text("**%s**" % name)
            super(RestFormatter, self).indent()
            self.write_text("*%s*" % desc)
            super(RestFormatter, self).dedent()

    def indent(self):
        self._indent_level += 1

    def dedent(self):
        self._indent_level -= 1

def guildfile_console_help(guildfile, model_desc=None):
    out = ConsoleFormatter()
    out.start_section("OVERVIEW")
    _write_console_help_overview(guildfile, model_desc, out)
    out.start_section("MODELS")
    _write_models(guildfile, out)
    return "".join(out.buffer)

def _write_console_help_overview(guildfile, model_desc, out):
    model_desc = model_desc or _format_guildfile_dir(guildfile)
    out.write_text(textwrap.dedent(
        """
        You are viewing help for models defined in %s.

        To run a model operation use 'guild run MODEL:OPERATION' where
        MODEL is one of the model names listed below and OPERATION is
        an associated operation.

        You may set operation flags using 'FLAG=VALUE' arguments to
        the run command. Refer to the operations below for a list of
        supported flags. Model flags apply to all operations.

        For more help, try 'guild run --help' or 'guild --help'.
        """
        % model_desc))

def _format_guildfile_dir(mf):
    if _is_cwd(mf.dir):
        return "the current directory"
    else:
        relpath = os.path.relpath(mf.dir)
        if relpath[0] != '.':
            relpath = os.path.join(".", relpath)
        return "'%s'" % relpath

def _is_cwd(path):
    return os.path.abspath(path) == os.path.abspath(os.getcwd())

def package_description(guildfile):
    out = RestFormatter()
    if guildfile.package:
        out.start_section(guildfile.package.name)
        _write_package_desc(guildfile.package, out)
    if guildfile.models:
        out.start_section("Models")
        _write_models(guildfile, out)
    return "".join(out.buffer)

def _write_package_desc(pkg, out):
    if pkg.description:
        out.write_description(pkg.description)
    if pkg.tags:
        out.write_paragraph()
        out.write_text("Keywords: %s" % " ".join(pkg.tags))

def _write_models(guildfile, out):
    i = 0
    for _name, model in sorted(guildfile.models.items()):
        if i > 0:
            out.write_paragraph()
        _write_model(model, out)
        i += 1

def _write_model(m, out):
    out.write_heading(m.name)
    out.indent()
    if m.description:
        out.write_paragraph()
        out.write_description(m.description)
    out.write_paragraph()
    _write_operations(m, out)
    out.write_paragraph()
    if m.references:
        _write_references(m.references, out)
    out.dedent()

def _write_operations(m, out):
    out.write_subheading("Operations")
    out.write_paragraph()
    out.indent()
    if m.operations:
        for i, op in enumerate(m.operations):
            if i > 0:
                out.write_paragraph()
            _write_operation(op, out)
    else:
        out.write_text(
            "No operations defined for this model")
    out.dedent()

def _write_operation(op, out):
    op = _maybe_apply_plugin_op(op)
    out.write_heading(op.name)
    out.indent()
    if op.description:
        out.write_paragraph()
        out.write_description(op.description)
    if op.flags:
        if op.description:
            out.write_paragraph()
        _write_flags(op.flags, "Flags", out)
    out.dedent()

def _maybe_apply_plugin_op(op):
    if op.plugin_op:
        for _name, plugin in pluginlib.iter_plugins():
            plugin_op = plugin.get_operation(op.plugin_op, op.modeldef, op)
            if plugin_op:
                return plugin_op
        log.warning(
            "Cannot find plugin op '%s' references in %s:%s",
            op.plugin_op, op.modeldef.name, op.name)
    return op

def _maybe_plugin_opdef(name, model, parent_opdef=None):
    for _name, plugin in pluginlib.iter_plugins():
        opdef = plugin.get_operation(name, model, parent_opdef)
        if opdef:
            return opdef
    return None

def _plugin_opdef(name, model, parent_opdef):
    opdef = _maybe_plugin_opdef(name, model, parent_opdef)
    if opdef is None:
        log.warning(
            "plugin-op '%s' specified by %s is not defined",
            parent_opdef.plugin_op.name, parent_opdef.fullname)
    return opdef

def _write_flags(flags, heading, out, no_flags_msg=None):
    out.write_subheading(heading)
    out.write_paragraph()
    out.indent()
    if flags:
        out.write_dl(flags_dl(flags), preserve_paragraphs=True)
    else:
        if no_flags_msg:
            out.write_description(no_flags_msg)
    out.dedent()

def flags_dl(flags):
    if not flags:
        return []
    max_flag_len = max([len(flag.name) for flag in flags])
    return [
        (flag.name, _format_flag_desc(flag, max_flag_len))
        for flag in flags
    ]

def _format_flag_desc(flag, max_flag_len):
    lines = flag.description.split("\n")
    if flag.default is not None:
        line1_suffix = " (%s)" % _default_label(flag.default)
    elif flag.required:
        line1_suffix = " (required)"
    elif flag.null_label:
        line1_suffix = " (%s)" % flag.null_label
    else:
        line1_suffix = ""
    lines[0] += line1_suffix
    if flag.choices:
        lines.append(_format_flag_choices(flag.choices, max_flag_len))
    if len(lines) > 1:
        return "\n\n".join(lines) + "\n\b\n"
    else:
        return lines[0]

def _default_label(val):
    return op_util.format_arg_value(val)

def _format_flag_choices(choices, max_flag_len):
    out = click.HelpFormatter()
    out.width = out.width - max_flag_len - 4
    out.write_heading("Choices")
    out.indent()
    out.write_dl(
        [(op_util.format_arg_value(choice.value),
          "\n\n".join(choice.description.split("\n")))
         for choice in choices],
        preserve_paragraphs=True)
    return "\n\b\n" + out.getvalue()

def _write_references(refs, out):
    out.write_subheading("References")
    out.write_paragraph()
    out.indent()
    for ref in refs:
        out.write_text("\b\n- %s" % ref)
    out.dedent()
<|endoftext|>