<commit_before># Copyright 2016 by Raytheon BBN Technologies Corp.  All Rights Reserved.
'''
Utilities for creating a basic channel configuration for testing.
'''

from QGL.ChannelLibraries import EdgeFactory, MeasFactory, QubitFactory
from QGL import ChannelLibraries
from QGL.Channels import Edge, Measurement
from QGL.PulseSequencer import Pulse, CompositePulse
from QGL.PatternUtils import flatten
from QGL.PulsePrimitives import Id, X, MEAS
from QGL.ControlFlow import qsync, qwait, ControlInstruction, Goto, Barrier
from QGL.BlockLabel import BlockLabel

from pyqgl2.test_cl import create_default_channelLibrary

import collections
from math import pi

def channel_setup(new=True):
    # new indicates replace any existing library
    # Otherwise if there is an existing library, use it
    # FIXME: For now, supplying first arg false meaning do not create physical channel mappings
    if not new and ChannelLibraries.channelLib is not None and len(ChannelLibraries.channelLib.keys()) != 0:
        create_default_channelLibrary(False, False)
        # create_channel_library(ChannelLibraries.channelLib.channelDict)
    else:
        create_default_channelLibrary(False, True)
        # create_channel_library(new=True)

# # OBE: Create a basic channel library
# # Code stolen from QGL's test_Sequences
# # It creates channels that are taken from test_Sequences APS2Helper
# def create_channel_library(channels=dict(), new=False):
#     from QGL.Channels import LogicalMarkerChannel, PhysicalQuadratureChannel, PhysicalMarkerChannel

#     ChannelLibraries.ChannelLibrary(blank=True)

#     qubit_names = ['q1','q2','q3']
#     logical_names = ['digitizerTrig', 'slaveTrig']

#     for name in logical_names:
#         channels[name] = LogicalMarkerChannel(label=name)

#     for name in qubit_names:
#         mName = 'M-' + name
#         mgName = 'M-' + name + '-gate'
#         qgName = name + '-gate'

#         mg = LogicalMarkerChannel(label=mgName)
#         qg = LogicalMarkerChannel(label=qgName)

#         m = MeasFactory(label=mName, gate_chan = mg, trig_chan=channels['digitizerTrig'])

#         q = QubitFactory(label=name, gate_chan=qg)
#         q.pulse_params['length'] = 30e-9
#         q.pulse_params['phase'] = pi/2

#         channels[name] = q
#         channels[mName] = m
#         channels[mgName]  = mg
#         channels[qgName]  = qg

#     # this block depends on the existence of q1 and q2
#     channels['cr-gate'] = LogicalMarkerChannel(label='cr-gate')

#     q1, q2 = channels['q1'], channels['q2']
#     cr = None
#     try:
#         cr = EdgeFactory(q1, q2)
#     except:
#         cr = Edge(label="cr", source = q1, target = q2, gate_chan = channels['cr-gate'] )
#     cr.pulse_params['length'] = 30e-9
#     cr.pulse_params['phase'] = pi/4
#     channels["cr"] = cr

#     mq1q2g = LogicalMarkerChannel(label='M-q1q2-gate')
#     channels['M-q1q2-gate']  = mq1q2g
#     channels['M-q1q2']       = Measurement(label='M-q1q2', gate_chan = mq1q2g, trig_chan=channels['digitizerTrig'])

#     # Add a 2nd edge from q2 back to q1 to support edgeTest4 (which is weird)
#     channels['cr2-gate'] = LogicalMarkerChannel(label='cr2-gate')
#     cr2 = None
#     try:
#         cr2 = EdgeFactory(q2, q1)
#     except:
#         cr2 = Edge(label="cr2", source = q2, target = q1, gate_chan = channels['cr2-gate'] )
#     cr2.pulse_params['length'] = 30e-9
#     cr2.pulse_params['phase'] = pi/4
#     channels["cr2"] = cr2

#     mq2q1g = LogicalMarkerChannel(label='M-q2q1-gate')
#     channels['M-q2q1-gate']  = mq2q1g
#     channels['M-q2q1']       = Measurement(label='M-q2q1', gate_chan = mq2q1g, trig_chan=channels['digitizerTrig'])

#     # Now assign physical channels
#     for name in ['APS1', 'APS2', 'APS3', 'APS4', 'APS5', 'APS6',
#                  'APS7', 'APS8', 'APS9', 'APS10']:
#         channelName = name + '-12'
#         channel = PhysicalQuadratureChannel(label=channelName)
#         channel.sampling_rate = 1.2e9
#         channel.instrument = name
#         channel.translator = 'APS2Pattern'
#         channels[channelName] = channel

#         for m in range(1,5):
#             channelName = "{0}-12m{1}".format(name,m)
#             channel = PhysicalMarkerChannel(label=channelName)
#             channel.sampling_rate = 1.2e9
#             channel.instrument = name
#             channel.translator = 'APS2Pattern'
#             channels[channelName] = channel

#     mapping = {	'digitizerTrig' : 'APS1-12m1',
#                 'slaveTrig'     : 'APS1-12m2',
#                 'q1'            : 'APS1-12',
#                 'q1-gate'       : 'APS1-12m3',
#                 'M-q1'          : 'APS2-12',
#                 'M-q1-gate'     : 'APS2-12m1',
#                 'q2'            : 'APS3-12',
#                 'q2-gate'       : 'APS3-12m1',
#                 'M-q2'          : 'APS4-12',
#                 'M-q2-gate'     : 'APS4-12m1',
#                 'q3'            : 'APS7-12',
#                 'q3-gate'       : 'APS7-12m1',
#                 'M-q3'          : 'APS8-12',
#                 'M-q3-gate'     : 'APS8-12m1',
#                 'cr'            : 'APS5-12',
#                 'cr-gate'       : 'APS5-12m1',
#                 'M-q1q2'        : 'APS6-12',
#                 'M-q1q2-gate'   : 'APS6-12m1',
#                 'cr2'           : 'APS9-12',
#                 'cr2-gate'      : 'APS9-12m1',
#                 'M-q2q1'        : 'APS10-12',
#                 'M-q2q1-gate'   : 'APS10-12m1'}

#     finalize_map(mapping, channels, new)
#     return channels

# # OBE: Store the given channels in the QGL ChannelLibraries
# def finalize_map(mapping, channels, new=False):
#     for name,value in mapping.items():
#         channels[name].phys_chan = channels[value]

#     if new:
#         ChannelLibraries.channelLib = ChannelLibraries.ChannelLibrary(blank=True)
#     ChannelLibraries.channelLib.channelDict = channels
#     ChannelLibraries.channelLib.build_connectivity_graph()

def discard_zero_Ids(seqs):
    # assume seqs has a structure like [[entry0, entry1, ..., entryN]]
    for seq in seqs:
        ct = 0
        while ct < len(seq):
            entry = seq[ct]
            if isinstance(entry, Pulse) and entry.label == "Id" and entry.length == 0:
                del seq[ct]
            else:
                ct += 1

# Things like echoCR create lists of pulses that need to be flattened
# before calling compile_to_hardware
def flattenSeqs(seq):
    hasList = False
    for el in seq:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, Pulse, CompositePulse)) :
            hasList = True
            break
    if hasList:
        newS = []
        for el in flatten(seq):
            newS.append(el)
        return newS
    else:
        return seq

def testable_sequence(seqs):
    '''
    Transform a QGL2 result function output into something more easily testable
    by flattening pulse lists.
    '''
    seqs = flattenSeqs(seqs)
    return seqs

def stripWaitBarrier(seqs):
    ''''
    QGL2 includes Waits and Barriers that are added after unit tests in QGL1, so strip them
    for comparison
    '''
    from QGL.ControlFlow import Barrier, Wait
    newS = []
    for el in seqs:
        if isinstance(el, Barrier) or isinstance(el, Wait):
            continue
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, Pulse, CompositePulse)) :
            newel = stripWaitBarrier(el)
            newS.extend(newel)
        else:
            newS.append(el)
    return newS

# Adapted from unittest.case.py: assertSequenceEqual
# Except use difflib.unified_diff instead of ndiff - much faster (less detail)
def assertPulseSequenceEqual(test, seq1, seq2, msg=None):
    """An equality assertion for ordered sequences of pulses.

    For the purposes of this function, a valid ordered sequence type is one
    which can be indexed, has a length, and has an equality operator.

    Args:
    seq1: The first sequence to compare.
    seq2: The second sequence to compare.
    msg: Optional message to use on failure instead of a list of
                    differences.
    """
    import difflib
    import pprint
    from unittest.util import safe_repr, _common_shorten_repr
    seq_type = list
    if seq_type is not None:
        seq_type_name = seq_type.__name__
        if not isinstance(seq1, seq_type):
            raise test.failureException('First sequence is not a %s: %s'
                                        % (seq_type_name, safe_repr(seq1)))
        if not isinstance(seq2, seq_type):
            raise test.failureException('Second sequence is not a %s: %s'
                                        % (seq_type_name, safe_repr(seq2)))
    else:
        seq_type_name = "sequence"

    differing = None
    try:
        len1 = len(seq1)
    except (TypeError, NotImplementedError):
        differing = 'First %s has no length.    Non-sequence?' % (
            seq_type_name)

    if differing is None:
        try:
            len2 = len(seq2)
        except (TypeError, NotImplementedError):
            differing = 'Second %s has no length.    Non-sequence?' % (
                seq_type_name)

    if differing is None:
        if seq1 == seq2:
            return

        differing = '%ss differ: %s != %s\n' % (
            (seq_type_name.capitalize(),) +
            _common_shorten_repr(seq1, seq2))

        for i in range(min(len1, len2)):
            try:
                item1 = seq1[i]
            except (TypeError, IndexError, NotImplementedError):
                differing += ('\nUnable to index element %d of first %s\n' %
                              (i, seq_type_name))
                break

            try:
                item2 = seq2[i]
            except (TypeError, IndexError, NotImplementedError):
                differing += ('\nUnable to index element %d of second %s\n' %
                                 (i, seq_type_name))
                break

            if item1 != item2:
                differing += ('\nFirst differing element %d:\n%s\n%s\n' %
                                 (i, str(item1), str(item2)))
                break
        else:
            if (len1 == len2 and seq_type is None and
                type(seq1) != type(seq2)):
                # The sequences are the same, but have differing types.
                return

        if len1 > len2:
            differing += ('\nFirst %s contains %d additional '
                          'elements.\n' % (seq_type_name, len1 - len2))
            try:
                differing += ('First extra element %d:\n%s\n' %
                              (len2, seq1[len2]))
            except (TypeError, IndexError, NotImplementedError):
                differing += ('Unable to index element %d '
                                  'of first %s\n' % (len2, seq_type_name))
        elif len1 < len2:
            differing += ('\nSecond %s contains %d additional '
                          'elements.\n' % (seq_type_name, len2 - len1))
            try:
                differing += ('First extra element %d:\n%s\n' %
                              (len1, seq2[len1]))
            except (TypeError, IndexError, NotImplementedError):
                differing += ('Unable to index element %d '
                                  'of second %s\n' % (len1, seq_type_name))
    standardMsg = differing
    diffMsg = '\n' + '\n'.join(
#            difflib.ndiff(pprint.pformat(seq1).splitlines(),
# FIXME: I wish I could get pprint.pformat to use str on pulses not repr
        difflib.unified_diff(pprint.pformat(seq1).splitlines(),
                             pprint.pformat(seq2).splitlines()))

    standardMsg = test._truncateMessage(standardMsg, diffMsg)
    msg = test._formatMessage(msg, standardMsg)
    test.fail(msg)

def get_cal_seqs_1qubit(qubit, calRepeats=2):
    '''
    Note: return may include 0 length Id pulses.
    EG:
    qwait
    Id(q1)
    MEAS(q1),
    qwait
    Id(q1)
    MEAS(q1),
    qwait
    X(q1)
    MEAS(q1),
    qwait
    X(q1)
    MEAS(q1)
    '''
    calSeq = []
    for pulse in [Id, X]:
        for _ in range(calRepeats):
            calSeq += [
                qwait(channels=(qubit,)),
                pulse(qubit),
                Barrier(qubit),
                MEAS(qubit)
            ]
    return calSeq

def get_cal_seqs_2qubits(q1, q2, calRepeats=2):
    '''
    Prepare all computational 2-qubit basis states and measure them.
    '''

    calseq = []
    for pulseSet in [(Id, Id), (Id, X), (X, Id), (X, X)]:
        for _ in range(calRepeats):
            calseq += [
                qwait(channels=(q1, q2)),
                pulseSet[0](q1),
                pulseSet[1](q2),
                Barrier(q1, q2),
                MEAS(q1),
                MEAS(q2)
            ]

    return calseq

def match_labels(seq1, seq2):
    '''
    Returns a copy of seq1 which replaces BlockLabels in seq1 with
    corresponding BlockLabels in seq2
    '''
    new_seq = []
    label_map = {}
    for s1, s2 in zip(seq1, seq2):
        if (isinstance(s1, BlockLabel) and isinstance(s2, BlockLabel)):
            new_seq.append(s2)
            label_map[s1] = s2
        else:
            new_seq.append(s1)

    for entry in new_seq:
        if isinstance(entry, Goto) and entry.target:
            entry.target = label_map[entry.target]
    return new_seq
<commit_msg>comment cleanup<commit_after># Copyright 2016 by Raytheon BBN Technologies Corp.  All Rights Reserved.
'''
Utilities for creating a basic channel configuration for testing.
'''

from QGL.ChannelLibraries import EdgeFactory, MeasFactory, QubitFactory
from QGL import ChannelLibraries
from QGL.Channels import Edge, Measurement
from QGL.PulseSequencer import Pulse, CompositePulse
from QGL.PatternUtils import flatten
from QGL.PulsePrimitives import Id, X, MEAS
from QGL.ControlFlow import qsync, qwait, ControlInstruction, Goto, Barrier
from QGL.BlockLabel import BlockLabel
#from QGL.Compiler import normalize

from pyqgl2.test_cl import create_default_channelLibrary

import collections
from math import pi

def channel_setup(new=True):
    # new indicates replace any existing library
    # Otherwise if there is an existing library, use it
    # FIXME: For now, supplying first arg false meaning do not create physical channel mappings
    if not new and ChannelLibraries.channelLib is not None and len(ChannelLibraries.channelLib.keys()) != 0:
        create_default_channelLibrary(False, False)
        # create_channel_library(ChannelLibraries.channelLib.channelDict)
    else:
        create_default_channelLibrary(False, True)
        # create_channel_library(new=True)

# # OBE: Create a basic channel library
# # Code stolen from QGL's test_Sequences
# # It creates channels that are taken from test_Sequences APS2Helper
# def create_channel_library(channels=dict(), new=False):
#     from QGL.Channels import LogicalMarkerChannel, PhysicalQuadratureChannel, PhysicalMarkerChannel

#     ChannelLibraries.ChannelLibrary(blank=True)

#     qubit_names = ['q1','q2','q3']
#     logical_names = ['digitizerTrig', 'slaveTrig']

#     for name in logical_names:
#         channels[name] = LogicalMarkerChannel(label=name)

#     for name in qubit_names:
#         mName = 'M-' + name
#         mgName = 'M-' + name + '-gate'
#         qgName = name + '-gate'

#         mg = LogicalMarkerChannel(label=mgName)
#         qg = LogicalMarkerChannel(label=qgName)

#         m = MeasFactory(label=mName, gate_chan = mg, trig_chan=channels['digitizerTrig'])

#         q = QubitFactory(label=name, gate_chan=qg)
#         q.pulse_params['length'] = 30e-9
#         q.pulse_params['phase'] = pi/2

#         channels[name] = q
#         channels[mName] = m
#         channels[mgName]  = mg
#         channels[qgName]  = qg

#     # this block depends on the existence of q1 and q2
#     channels['cr-gate'] = LogicalMarkerChannel(label='cr-gate')

#     q1, q2 = channels['q1'], channels['q2']
#     cr = None
#     try:
#         cr = EdgeFactory(q1, q2)
#     except:
#         cr = Edge(label="cr", source = q1, target = q2, gate_chan = channels['cr-gate'] )
#     cr.pulse_params['length'] = 30e-9
#     cr.pulse_params['phase'] = pi/4
#     channels["cr"] = cr

#     mq1q2g = LogicalMarkerChannel(label='M-q1q2-gate')
#     channels['M-q1q2-gate']  = mq1q2g
#     channels['M-q1q2']       = Measurement(label='M-q1q2', gate_chan = mq1q2g, trig_chan=channels['digitizerTrig'])

#     # Add a 2nd edge from q2 back to q1 to support edgeTest4 (which is weird)
#     channels['cr2-gate'] = LogicalMarkerChannel(label='cr2-gate')
#     cr2 = None
#     try:
#         cr2 = EdgeFactory(q2, q1)
#     except:
#         cr2 = Edge(label="cr2", source = q2, target = q1, gate_chan = channels['cr2-gate'] )
#     cr2.pulse_params['length'] = 30e-9
#     cr2.pulse_params['phase'] = pi/4
#     channels["cr2"] = cr2

#     mq2q1g = LogicalMarkerChannel(label='M-q2q1-gate')
#     channels['M-q2q1-gate']  = mq2q1g
#     channels['M-q2q1']       = Measurement(label='M-q2q1', gate_chan = mq2q1g, trig_chan=channels['digitizerTrig'])

#     # Now assign physical channels
#     for name in ['APS1', 'APS2', 'APS3', 'APS4', 'APS5', 'APS6',
#                  'APS7', 'APS8', 'APS9', 'APS10']:
#         channelName = name + '-12'
#         channel = PhysicalQuadratureChannel(label=channelName)
#         channel.sampling_rate = 1.2e9
#         channel.instrument = name
#         channel.translator = 'APS2Pattern'
#         channels[channelName] = channel

#         for m in range(1,5):
#             channelName = "{0}-12m{1}".format(name,m)
#             channel = PhysicalMarkerChannel(label=channelName)
#             channel.sampling_rate = 1.2e9
#             channel.instrument = name
#             channel.translator = 'APS2Pattern'
#             channels[channelName] = channel

#     mapping = {	'digitizerTrig' : 'APS1-12m1',
#                 'slaveTrig'     : 'APS1-12m2',
#                 'q1'            : 'APS1-12',
#                 'q1-gate'       : 'APS1-12m3',
#                 'M-q1'          : 'APS2-12',
#                 'M-q1-gate'     : 'APS2-12m1',
#                 'q2'            : 'APS3-12',
#                 'q2-gate'       : 'APS3-12m1',
#                 'M-q2'          : 'APS4-12',
#                 'M-q2-gate'     : 'APS4-12m1',
#                 'q3'            : 'APS7-12',
#                 'q3-gate'       : 'APS7-12m1',
#                 'M-q3'          : 'APS8-12',
#                 'M-q3-gate'     : 'APS8-12m1',
#                 'cr'            : 'APS5-12',
#                 'cr-gate'       : 'APS5-12m1',
#                 'M-q1q2'        : 'APS6-12',
#                 'M-q1q2-gate'   : 'APS6-12m1',
#                 'cr2'           : 'APS9-12',
#                 'cr2-gate'      : 'APS9-12m1',
#                 'M-q2q1'        : 'APS10-12',
#                 'M-q2q1-gate'   : 'APS10-12m1'}

#     finalize_map(mapping, channels, new)
#     return channels

# # OBE: Store the given channels in the QGL ChannelLibraries
# def finalize_map(mapping, channels, new=False):
#     for name,value in mapping.items():
#         channels[name].phys_chan = channels[value]

#     if new:
#         ChannelLibraries.channelLib = ChannelLibraries.ChannelLibrary(blank=True)
#     ChannelLibraries.channelLib.channelDict = channels
#     ChannelLibraries.channelLib.build_connectivity_graph()

def discard_zero_Ids(seqs):
    # assume seqs has a structure like [[entry0, entry1, ..., entryN]]
    for seq in seqs:
        ct = 0
        while ct < len(seq):
            entry = seq[ct]
            if isinstance(entry, Pulse) and entry.label == "Id" and entry.length == 0:
                del seq[ct]
            else:
                ct += 1

# Things like echoCR create lists of pulses that need to be flattened
# before calling compile_to_hardware
def flattenSeqs(seq):
    hasList = False
    for el in seq:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, Pulse, CompositePulse)) :
            hasList = True
            break
    if hasList:
        newS = []
        for el in flatten(seq):
            newS.append(el)
        return newS
    else:
        return seq

def testable_sequence(seqs):
    '''
    Transform a QGL2 result function output into something more easily testable
    by flattening pulse lists.
    '''
    seqs = flattenSeqs(seqs)
#    seqs = normalize(seqs, None)
    return seqs

def stripWaitBarrier(seqs):
    ''''
    QGL2 includes Waits and Barriers that are added after unit tests in QGL1, so strip them
    for comparison. Note however that Barrier;Pulse is how QGL2 does QGL1 PulseBlock(pulses).
    '''
    from QGL.ControlFlow import Barrier, Wait
    newS = []
    for el in seqs:
        if isinstance(el, Barrier) or isinstance(el, Wait):
            continue
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, Pulse, CompositePulse)) :
            newel = stripWaitBarrier(el)
            newS.extend(newel)
        else:
            newS.append(el)
    return newS

# Adapted from unittest.case.py: assertSequenceEqual
# Except use difflib.unified_diff instead of ndiff - much faster (less detail)
# Note QGL2 uses Barriers to force concurrency where QGL1 might use PulseBlock; that will look different.
def assertPulseSequenceEqual(test, seq1, seq2, msg=None):
    """An equality assertion for ordered sequences of pulses.

    For the purposes of this function, a valid ordered sequence type is one
    which can be indexed, has a length, and has an equality operator.

    Args:
    seq1: The first sequence to compare.
    seq2: The second sequence to compare.
    msg: Optional message to use on failure instead of a list of
                    differences.
    """
    import difflib
    import pprint
    from unittest.util import safe_repr, _common_shorten_repr
    seq_type = list
    if seq_type is not None:
        seq_type_name = seq_type.__name__
        if not isinstance(seq1, seq_type):
            raise test.failureException('First sequence is not a %s: %s'
                                        % (seq_type_name, safe_repr(seq1)))
        if not isinstance(seq2, seq_type):
            raise test.failureException('Second sequence is not a %s: %s'
                                        % (seq_type_name, safe_repr(seq2)))
    else:
        seq_type_name = "sequence"

    differing = None
    try:
        len1 = len(seq1)
    except (TypeError, NotImplementedError):
        differing = 'First %s has no length.    Non-sequence?' % (
            seq_type_name)

    if differing is None:
        try:
            len2 = len(seq2)
        except (TypeError, NotImplementedError):
            differing = 'Second %s has no length.    Non-sequence?' % (
                seq_type_name)

    if differing is None:
        if seq1 == seq2:
            return

        differing = '%ss differ: %s != %s\n' % (
            (seq_type_name.capitalize(),) +
            _common_shorten_repr(seq1, seq2))

        for i in range(min(len1, len2)):
            try:
                item1 = seq1[i]
            except (TypeError, IndexError, NotImplementedError):
                differing += ('\nUnable to index element %d of first %s\n' %
                              (i, seq_type_name))
                break

            try:
                item2 = seq2[i]
            except (TypeError, IndexError, NotImplementedError):
                differing += ('\nUnable to index element %d of second %s\n' %
                                 (i, seq_type_name))
                break

            if item1 != item2:
                differing += ('\nFirst differing element %d:\n%s\n%s\n' %
                                 (i, str(item1), str(item2)))
                break
        else:
            if (len1 == len2 and seq_type is None and
                type(seq1) != type(seq2)):
                # The sequences are the same, but have differing types.
                return

        if len1 > len2:
            differing += ('\nFirst %s contains %d additional '
                          'elements.\n' % (seq_type_name, len1 - len2))
            try:
                differing += ('First extra element %d:\n%s\n' %
                              (len2, seq1[len2]))
            except (TypeError, IndexError, NotImplementedError):
                differing += ('Unable to index element %d '
                                  'of first %s\n' % (len2, seq_type_name))
        elif len1 < len2:
            differing += ('\nSecond %s contains %d additional '
                          'elements.\n' % (seq_type_name, len2 - len1))
            try:
                differing += ('First extra element %d:\n%s\n' %
                              (len1, seq2[len1]))
            except (TypeError, IndexError, NotImplementedError):
                differing += ('Unable to index element %d '
                                  'of second %s\n' % (len1, seq_type_name))
    standardMsg = differing
    diffMsg = '\n' + '\n'.join(
#            difflib.ndiff(pprint.pformat(seq1).splitlines(),
# FIXME: I wish I could get pprint.pformat to use str on pulses not repr
        difflib.unified_diff(pprint.pformat(seq1).splitlines(),
                             pprint.pformat(seq2).splitlines()))

    standardMsg = test._truncateMessage(standardMsg, diffMsg)
    msg = test._formatMessage(msg, standardMsg)
    test.fail(msg)

def get_cal_seqs_1qubit(qubit, calRepeats=2):
    '''
    Note: return may include 0 length Id pulses.
    EG:
    qwait
    Id(q1)
    MEAS(q1),
    qwait
    Id(q1)
    MEAS(q1),
    qwait
    X(q1)
    MEAS(q1),
    qwait
    X(q1)
    MEAS(q1)
    '''
    calSeq = []
    for pulse in [Id, X]:
        for _ in range(calRepeats):
            calSeq += [
                qwait(channels=(qubit,)),
                pulse(qubit),
                Barrier(qubit),
                MEAS(qubit)
            ]
    return calSeq

def get_cal_seqs_2qubits(q1, q2, calRepeats=2):
    '''
    Prepare all computational 2-qubit basis states and measure them.
    '''

    calseq = []
    for pulseSet in [(Id, Id), (Id, X), (X, Id), (X, X)]:
        for _ in range(calRepeats):
            calseq += [
                qwait(channels=(q1, q2)),
                pulseSet[0](q1),
                pulseSet[1](q2),
                Barrier(q1, q2),
                MEAS(q1),
                MEAS(q2)
            ]

    return calseq

def match_labels(seq1, seq2):
    '''
    Returns a copy of seq1 which replaces BlockLabels in seq1 with
    corresponding BlockLabels in seq2
    '''
    new_seq = []
    label_map = {}
    for s1, s2 in zip(seq1, seq2):
        if (isinstance(s1, BlockLabel) and isinstance(s2, BlockLabel)):
            new_seq.append(s2)
            label_map[s1] = s2
        else:
            new_seq.append(s1)

    for entry in new_seq:
        if isinstance(entry, Goto) and entry.target:
            entry.target = label_map[entry.target]
    return new_seq
<|endoftext|>


<commit_before><commit_msg>忽略非opened, closed, reopened的PR<commit_after><|endoftext|>


<commit_before># Copyright 2015 by Raytheon BBN Technologies Corp.  All Rights Reserved

"""
Convenience classes that simplify creating useful warning/error
messages when using the standard Python ast module to examine,
transform, or create a Python parse tree
"""

import ast
import meta
import os
import sys
import traceback

from copy import deepcopy

from pyqgl2.pysourcegen import python_source, dump_python_source

class NodeError(object):
    """
    A mix-in to make it simplify the generation of
    consistent, meaningful error and warning messages
    within the ast.NodeTransformer and ast.NodeVisitor
    classes

    Assumes that the node parameter to its methods is
    an instance of an ast.AST, and has been annotated
    with the name of the source file (as node.qgl_fname)

    The methods are implemented with module methods (below)
    so that they don't need to be called from a
    Visitor/Transformer.
    """

    NODE_ERROR_NONE = 0
    NODE_ERROR_WARNING = 1
    NODE_ERROR_ERROR = 2
    NODE_ERROR_FATAL = 3

    NODE_ERROR_LEGAL_LEVELS = {
        NODE_ERROR_NONE : 'diag',
        NODE_ERROR_WARNING : 'warning',
        NODE_ERROR_ERROR : 'error',
        NODE_ERROR_FATAL : 'fatal'
    }

    MAX_ERR_LEVEL = NODE_ERROR_NONE

    LAST_DIAG_MSG = ''
    LAST_WARNING_MSG = ''
    LAST_ERROR_MSG = ''
    LAST_FATAL_MSG = ''

    ALL_PRINTED = set()

    def __init__(self):
        NodeError.MAX_ERR_LEVEL = NodeError.NODE_ERROR_NONE

    @staticmethod
    def reset():
        LAST_DIAG_MSG = ''
        LAST_WARNING_MSG = ''
        LAST_ERROR_MSG = ''
        LAST_FATAL_MSG = ''
        ALL_PRINTED = set()

    @staticmethod
    def halt_on_error():
        """
        The ordinary use of NodeError is to continue on after encountering
        an error (in the hope of getting useful additional diagnostics).

        At certain points in the program, however, it makes little sense
        to continue if there has been an error in an earlier part of
        the program.  Use halt_on_error() to detect this condition and
        halt.
        """

        if NodeError.MAX_ERR_LEVEL >= NodeError.NODE_ERROR_ERROR:
            sys.exit(1)

    @staticmethod
    def diag_msg(node, msg=None):
        """
        Print a diagnostic message associated with the given node
        """

        LAST_DIAG_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_NONE, msg)

    @staticmethod
    def warning_msg(node, msg=None):
        """
        Print a warning message associated with the given node
        """

        LAST_WARNING_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_WARNING, msg)

    @staticmethod
    def error_msg(node, msg=None):
        """
        Print an error message associated with the given node
        """

        LAST_ERROR_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_ERROR, msg)

    @staticmethod
    def fatal_msg(node, msg=None):
        """
        Print an fatal error message associated with the given node
        """

        LAST_FATAL_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_FATAL, msg)

    @staticmethod
    def _make_msg(node, level, msg=None):
        """
        Helper function that does all the real work of formatting
        the messages, updating the max error level observed, and
        exiting when a fatal error is encountered

        Does basic sanity checking on its inputs to make sure that
        the function is called correctly
        """

        # Detect improper usage, and bomb out
        if node:
            assert isinstance(node, ast.AST)

        assert level in NodeError.NODE_ERROR_LEGAL_LEVELS

        if not msg:
            msg = '?'

        if level > NodeError.MAX_ERR_LEVEL:
            NodeError.MAX_ERR_LEVEL = level

        if level in NodeError.NODE_ERROR_LEGAL_LEVELS:
            level_str = NodeError.NODE_ERROR_LEGAL_LEVELS[level]
        else:
            level_str = 'weird'

        if node:
            if hasattr(node, 'qgl_fname'):
                qgl_fname = node.qgl_fname
            else:
                qgl_fname = '<unknown>'

            text = ('%s:%d:%d: ' %
                    (qgl_fname, node.lineno, node.col_offset))
        else:
            text = ''

        text += ('%s: %s' % (level_str, msg))

        # Keep track of what we've printed, so we don't
        # print it over and over again (for repeated
        # substitions, inlining, or loop unrolling)
        #
        if text not in NodeError.ALL_PRINTED:
            print('%s' % text)
            NodeError.ALL_PRINTED.add(text)

        # If we've encountered a fatal error, then there's no
        # point in continuing: exit immediately.
        if NodeError.MAX_ERR_LEVEL == NodeError.NODE_ERROR_FATAL:
            sys.exit(1)

# See NodeError above for more description.  These methods
# are deprecated in favor of the NodeError interface, but
# remain for backward compatibility.

def diag_msg(node, msg=None):
    """
    Print a diagnostic message associated with the given node
    """
    NodeError.diag_msg(node, msg)

def warning_msg(node, msg=None):
    """
    Print a warning message associated with the given node
    """
    NodeError.warning_msg(node, msg)

def error_msg(node, msg=None):
    """
    Print an error message associated with the given node
    """
    NodeError.error_msg(node, msg)

def fatal_msg(node, msg=None):
    """
    Print an fatal error message associated with the given node
    """
    NodeError.fatal_msg(node, msg)

def debug_msg(msg, level=0, tag=None):
    """
    Print a debug msg, labeled with the filename, line number, and
    function name that invoked debug_msg

    Debug messages can be suppressed so that only messages that
    match one of a set of tags, or that at a level greater than or
    equal to a global threshold, are printed.

    TODO: tags and levels are not supported yet; all messages are
    printed
    """

    (filename, lineno, funcname, code) = traceback.extract_stack(limit=2)[0]

    text = ('DEBUG-%d: %s:%d (%s) %s' %
            (level, os.path.relpath(filename), lineno, funcname, msg))

    print('%s' % text)

class NodeTransformerWithFname(ast.NodeTransformer, NodeError):
    """
    ast.NodeTransformer with NodeError mixed in
    """

    def __init__(self):
        super(NodeTransformerWithFname, self).__init__()

class NodeVisitorWithFname(ast.NodeVisitor, NodeError):
    """
    ast.NodeVisitor with NodeError mixed in
    """

    def __init__(self):
        super(NodeVisitorWithFname, self).__init__()

def copy_node(node):
    """
    Make a copy of the given ast node and its descendants
    so that the copy can be manipulated without altering
    the original

    Hopefully deepcopy() is sufficient
    """

    return deepcopy(node)

def ast2str(ptree):
    """
    Given an AST parse tree, return the equivalent code
    (as a string)
    """

    return dump_python_source(ptree)

def copy_all_loc(new_node, old_node, recurse=False):
    """
    Like ast.copy_location, but also copies other fields added
    by pyqgl2, if present

    If recurse is not False, then recursively copy the location
    from old_node to each node within new_node

    Currently the only new pyqgl2 field is qgl_fname, but
    there will probably be others
    """

    assert isinstance(new_node, ast.AST)
    assert isinstance(old_node, ast.AST)

    if not recurse:
        ast.copy_location(new_node, old_node)

        if hasattr(old_node, 'qgl_fname'):
            new_node.qgl_fname = old_node.qgl_fname
    else:
        for subnode in ast.walk(new_node):
            ast.copy_location(subnode, old_node)

            if hasattr(old_node, 'qgl_fname'):
                subnode.qgl_fname = old_node.qgl_fname

    return new_node

<commit_msg>move debug_msg to debug.py; clean up flakes<commit_after># Copyright 2015 by Raytheon BBN Technologies Corp.  All Rights Reserved

"""
Convenience classes that simplify creating useful warning/error
messages when using the standard Python ast module to examine,
transform, or create a Python parse tree
"""

import ast
import sys

from copy import deepcopy

from pyqgl2.pysourcegen import dump_python_source

class NodeError(object):
    """
    A mix-in to make it simplify the generation of
    consistent, meaningful error and warning messages
    within the ast.NodeTransformer and ast.NodeVisitor
    classes

    Assumes that the node parameter to its methods is
    an instance of an ast.AST, and has been annotated
    with the name of the source file (as node.qgl_fname)

    The methods are implemented with module methods (below)
    so that they don't need to be called from a
    Visitor/Transformer.
    """

    NODE_ERROR_NONE = 0
    NODE_ERROR_WARNING = 1
    NODE_ERROR_ERROR = 2
    NODE_ERROR_FATAL = 3

    NODE_ERROR_LEGAL_LEVELS = {
        NODE_ERROR_NONE : 'diag',
        NODE_ERROR_WARNING : 'warning',
        NODE_ERROR_ERROR : 'error',
        NODE_ERROR_FATAL : 'fatal'
    }

    MAX_ERR_LEVEL = NODE_ERROR_NONE

    LAST_DIAG_MSG = ''
    LAST_WARNING_MSG = ''
    LAST_ERROR_MSG = ''
    LAST_FATAL_MSG = ''

    ALL_PRINTED = set()

    def __init__(self):
        NodeError.MAX_ERR_LEVEL = NodeError.NODE_ERROR_NONE

    @staticmethod
    def reset():
        NodeError.LAST_DIAG_MSG = ''
        NodeError.LAST_WARNING_MSG = ''
        NodeError.LAST_ERROR_MSG = ''
        NodeError.LAST_FATAL_MSG = ''
        NodeError.ALL_PRINTED = set()

    @staticmethod
    def halt_on_error():
        """
        The ordinary use of NodeError is to continue on after encountering
        an error (in the hope of getting useful additional diagnostics).

        At certain points in the program, however, it makes little sense
        to continue if there has been an error in an earlier part of
        the program.  Use halt_on_error() to detect this condition and
        halt.
        """

        if NodeError.MAX_ERR_LEVEL >= NodeError.NODE_ERROR_ERROR:
            sys.exit(1)

    @staticmethod
    def diag_msg(node, msg=None):
        """
        Print a diagnostic message associated with the given node
        """

        NodeError.LAST_DIAG_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_NONE, msg)

    @staticmethod
    def warning_msg(node, msg=None):
        """
        Print a warning message associated with the given node
        """

        NodeError.LAST_WARNING_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_WARNING, msg)

    @staticmethod
    def error_msg(node, msg=None):
        """
        Print an error message associated with the given node
        """

        NodeError.LAST_ERROR_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_ERROR, msg)

    @staticmethod
    def fatal_msg(node, msg=None):
        """
        Print an fatal error message associated with the given node
        """

        NodeError.LAST_FATAL_MSG = msg
        NodeError._make_msg(node, NodeError.NODE_ERROR_FATAL, msg)

    @staticmethod
    def _make_msg(node, level, msg=None):
        """
        Helper function that does all the real work of formatting
        the messages, updating the max error level observed, and
        exiting when a fatal error is encountered

        Does basic sanity checking on its inputs to make sure that
        the function is called correctly
        """

        # Detect improper usage, and bomb out
        if node:
            assert isinstance(node, ast.AST)

        assert level in NodeError.NODE_ERROR_LEGAL_LEVELS

        if not msg:
            msg = '?'

        if level > NodeError.MAX_ERR_LEVEL:
            NodeError.MAX_ERR_LEVEL = level

        if level in NodeError.NODE_ERROR_LEGAL_LEVELS:
            level_str = NodeError.NODE_ERROR_LEGAL_LEVELS[level]
        else:
            level_str = 'weird'

        if node:
            if hasattr(node, 'qgl_fname'):
                qgl_fname = node.qgl_fname
            else:
                qgl_fname = '<unknown>'

            text = ('%s:%d:%d: ' %
                    (qgl_fname, node.lineno, node.col_offset))
        else:
            text = ''

        text += ('%s: %s' % (level_str, msg))

        # Keep track of what we've printed, so we don't
        # print it over and over again (for repeated
        # substitions, inlining, or loop unrolling)
        #
        if text not in NodeError.ALL_PRINTED:
            print('%s' % text)
            NodeError.ALL_PRINTED.add(text)

        # If we've encountered a fatal error, then there's no
        # point in continuing: exit immediately.
        if NodeError.MAX_ERR_LEVEL == NodeError.NODE_ERROR_FATAL:
            sys.exit(1)

# See NodeError above for more description.  These methods
# are deprecated in favor of the NodeError interface, but
# remain for backward compatibility.

def diag_msg(node, msg=None):
    """
    Print a diagnostic message associated with the given node
    """
    NodeError.diag_msg(node, msg)

def warning_msg(node, msg=None):
    """
    Print a warning message associated with the given node
    """
    NodeError.warning_msg(node, msg)

def error_msg(node, msg=None):
    """
    Print an error message associated with the given node
    """
    NodeError.error_msg(node, msg)

def fatal_msg(node, msg=None):
    """
    Print an fatal error message associated with the given node
    """
    NodeError.fatal_msg(node, msg)

class NodeTransformerWithFname(ast.NodeTransformer, NodeError):
    """
    ast.NodeTransformer with NodeError mixed in
    """

    def __init__(self):
        super(NodeTransformerWithFname, self).__init__()

class NodeVisitorWithFname(ast.NodeVisitor, NodeError):
    """
    ast.NodeVisitor with NodeError mixed in
    """

    def __init__(self):
        super(NodeVisitorWithFname, self).__init__()

def copy_node(node):
    """
    Make a copy of the given ast node and its descendants
    so that the copy can be manipulated without altering
    the original

    Hopefully deepcopy() is sufficient
    """

    return deepcopy(node)

def ast2str(ptree):
    """
    Given an AST parse tree, return the equivalent code
    (as a string)
    """

    return dump_python_source(ptree)

def copy_all_loc(new_node, old_node, recurse=False):
    """
    Like ast.copy_location, but also copies other fields added
    by pyqgl2, if present

    If recurse is not False, then recursively copy the location
    from old_node to each node within new_node

    Currently the only new pyqgl2 field is qgl_fname, but
    there will probably be others
    """

    assert isinstance(new_node, ast.AST)
    assert isinstance(old_node, ast.AST)

    if not recurse:
        ast.copy_location(new_node, old_node)

        if hasattr(old_node, 'qgl_fname'):
            new_node.qgl_fname = old_node.qgl_fname
    else:
        for subnode in ast.walk(new_node):
            ast.copy_location(subnode, old_node)

            if hasattr(old_node, 'qgl_fname'):
                subnode.qgl_fname = old_node.qgl_fname

    return new_node

<|endoftext|>


<commit_before>from pymongo import MongoClient

class Connection(object):
    def __init__(self, host, port):
        self.mongo_client = MongoClient(host, port)
        self.db = self.mongo_client.monad
        self.nodes_collection = self.db.Nodes
        self.points_collection = self.db.Points
        self.ways_collection = self.db.Ways
        self.bus_stops_collection = self.db.BusStops
        self.edges_collection = self.db.Edges
        self.address_book_collection = self.db.AddressBook

    # Functions of Nodes
    def insert_node(self, osm_id, tags, point):
        self.nodes_collection.insert_one({'osm_id': osm_id, 'tags': tags,
                                          'point': {'longitude': point.longitude, 'latitude': point.latitude}})

    def find_node(self, osm_id):
        return self.nodes_collection.find_one({'osm_id': osm_id})

    def delete_node(self, osm_id):
        result = self.nodes_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

    # Functions of Points
    def insert_point(self, osm_id, point):
        self.points_collection.insert_one({'osm_id': osm_id,
                                           'point': {'longitude': point.longitude, 'latitude': point.latitude}})

    def find_point(self, osm_id):
        return self.points_collection.find_one({'osm_id': osm_id})

    def delete_point(self, osm_id):
        result = self.points_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

    # Functions of Ways
    def insert_way(self, osm_id, tags, references):
        self.ways_collection.insert_one({'osm_id': osm_id, 'tags': tags, 'references': references})

    def find_way(self, osm_id):
        return self.ways_collection.find_one({'osm_id': osm_id})

    def delete_way(self, osm_id):
        result = self.ways_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

if __name__ == '__main__':
    connection = Connection(host='127.0.0.1', port=27017)
    # connection.insert_node(osm_id=1, tags='hi', point={'longitude': 1.0, 'latitude': 2.0})
    # print connection.delete_node(osm_id=1)
<commit_msg>Adding functions to connections.py<commit_after>from pymongo import MongoClient

class Connection(object):
    def __init__(self, host, port):
        self.mongo_client = MongoClient(host, port)
        self.db = self.mongo_client.monad
        self.nodes_collection = self.db.Nodes
        self.points_collection = self.db.Points
        self.ways_collection = self.db.Ways
        self.bus_stops_collection = self.db.BusStops
        self.edges_collection = self.db.Edges
        self.address_book_collection = self.db.AddressBook

    # Functions of nodes
    def insert_node(self, osm_id, tags, point):
        document = {'osm_id': osm_id, 'tags': tags, 'point': {'longitude': point.longitude, 'latitude': point.latitude}}
        result = self.nodes_collection.insert_one(document)
        return result.inserted_id

    def find_node(self, osm_id):
        return self.nodes_collection.find_one({'osm_id': osm_id})

    def delete_node(self, osm_id):
        result = self.nodes_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

    # Functions of points
    def insert_point(self, osm_id, point):
        document = {'osm_id': osm_id, 'point': {'longitude': point.longitude, 'latitude': point.latitude}}
        result = self.points_collection.insert_one(document)
        return result.inserted_id

    def find_point(self, osm_id):
        return self.points_collection.find_one({'osm_id': osm_id})

    def delete_point(self, osm_id):
        result = self.points_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

    # Functions of ways
    def insert_way(self, osm_id, tags, references):
        document = {'osm_id': osm_id, 'tags': tags, 'references': references}
        result = self.ways_collection.insert_one(document)
        return result.inserted_id

    def find_way(self, osm_id):
        return self.ways_collection.find_one({'osm_id': osm_id})

    def delete_way(self, osm_id):
        result = self.ways_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

    # Functions of bus_stops
    def insert_bus_stop(self, osm_id, name, point):
        document = {'osm_id': osm_id, 'name': name, 'point': {'longitude': point.longitude, 'latitude': point.latitude}}
        result = self.bus_stops_collection.insert_one(document)
        return result.inserted_id

    def find_bus_stop(self, osm_id):
        return self.bus_stops_collection.find_one({'osm_id': osm_id})

    def delete_bus_stop(self, osm_id):
        result = self.bus_stops_collection.delete_one({'osm_id': osm_id})
        return result.deleted_count

    # Functions of edges
    def insert_edge(self, from_node, to_node, max_speed, road_type, way_id, traffic_density=None):
        if traffic_density is None:
            traffic_density = 0

        document = {'from_node': from_node, 'to_node': to_node, 'max_speed': max_speed, 'road_type': road_type,
                    'way_id': way_id, 'traffic_density': traffic_density}
        result = self.edges_collection.insert_one(document)
        return result.inserted_id

    def find_edge(self, from_node, to_node):
        return self.edges_collection.find_one({'from_node': from_node, 'to_node': to_node})

    def find_edges(self, from_node):
        return self.edges_collection.find({'from_node': from_node})

    def delete_edge(self, from_node, to_node):
        result = self.edges_collection.delete_one({'from_node': from_node, 'to_node': to_node})
        return result.deleted_count

    def delete_edges(self, from_node):
        result = self.edges_collection.delete({'from_node': from_node})
        return result.deleted_count

    # Functions of address_book
    def insert_address(self, name, node_id, point):
        if name is None or name == '' or node_id is None or point is None:
            return

        document = {'name': name, 'node_id': node_id,
                    'point': {'longitude': point.longitude, 'latitude': point.latitude}}

        result = self.address_book_collection.insert_one(document)
        return result.inserted_id

    def find_address(self, name):
        return self.address_book_collection.find({'name': name})

    def delete_address(self, name):
        result = self.address_book_collection.delete({'name': name})
        return result.deleted_count

if __name__ == '__main__':
    connection = Connection(host='127.0.0.1', port=27017)
    # connection.insert_node(osm_id=1, tags='hi', point={'longitude': 1.0, 'latitude': 2.0})
    # print connection.delete_node(osm_id=1)
<|endoftext|>


<commit_before># Copyright 2020 Google, LLC.
#
# 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 os
from dotenv import load_dotenv
from google.protobuf.duration_pb2 import Duration

METRIC_NAME = 'integ-test-metric'
METRIC_PATH = f'custom.googleapis.com/{METRIC_NAME}'
RESOURCE_TYPE = 'gce_instance'
INSTANCE_ID = '1234567890123456789'
ZONE = 'us-central1-f'
ALERT_POLICY_NAME = 'integ-test-policy'
TRIGGER_NOTIFICATION_THRESHOLD_DOUBLE = 3.0
PROJECT_ID = os.environ['PROJECT_ID']

TEST_METRIC_DESCRIPTOR = {
    'type': f'custom.googleapis.com/{METRIC_NAME}',
    'metric_kind': 'GAUGE',
    'value_type': 'DOUBLE',
    'description': 'A custom metric meant for testing purposes'
}

TEST_NOTIFICATION_CHANNEL = {
    'type': 'pubsub',
    'display_name': 'test channel',
    'description': 'A Pub/Sub channel meant for testing purposes',
    'labels': {
        'topic': f'projects/{PROJECT_ID}/topics/tf-topic'
    }
}

TEST_ALERT_POLICY_TEMPLATE = {
    'display_name': ALERT_POLICY_NAME,
    'user_labels': {'type': 'test_policy', 'metric': METRIC_NAME},
    'combiner': 'AND',
    'conditions': [{
        'display_name': 'test condition',
        'condition_threshold': {
            'filter': f'metric.type = "{METRIC_PATH}" AND resource.type = "{RESOURCE_TYPE}"',
            'comparison': 'COMPARISON_GT',
            'threshold_value': TRIGGER_NOTIFICATION_THRESHOLD_DOUBLE,
            'duration': Duration(seconds=0),
        }
    }],
    'notification_channels': []
}

TEST_SERIES = {
    'metric': {
        'type': METRIC_PATH,
    },
    'resource': {
        'type': RESOURCE_TYPE,
        'labels': {
            'instance_id': INSTANCE_ID,
            'zone': ZONE
        }
    }
}<commit_msg>test with hardcoded project<commit_after># Copyright 2020 Google, LLC.
#
# 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 os
from dotenv import load_dotenv
from google.protobuf.duration_pb2 import Duration

METRIC_NAME = 'integ-test-metric'
METRIC_PATH = f'custom.googleapis.com/{METRIC_NAME}'
RESOURCE_TYPE = 'gce_instance'
INSTANCE_ID = '1234567890123456789'
ZONE = 'us-central1-f'
ALERT_POLICY_NAME = 'integ-test-policy'
TRIGGER_NOTIFICATION_THRESHOLD_DOUBLE = 3.0
# PROJECT_ID = os.environ['PROJECT_ID']
PROJECT_ID = 'mon-notif-hue-integ-staging'

TEST_METRIC_DESCRIPTOR = {
    'type': f'custom.googleapis.com/{METRIC_NAME}',
    'metric_kind': 'GAUGE',
    'value_type': 'DOUBLE',
    'description': 'A custom metric meant for testing purposes'
}

TEST_NOTIFICATION_CHANNEL = {
    'type': 'pubsub',
    'display_name': 'test channel',
    'description': 'A Pub/Sub channel meant for testing purposes',
    'labels': {
        'topic': f'projects/{PROJECT_ID}/topics/tf-topic'
    }
}

TEST_ALERT_POLICY_TEMPLATE = {
    'display_name': ALERT_POLICY_NAME,
    'user_labels': {'type': 'test_policy', 'metric': METRIC_NAME},
    'combiner': 'AND',
    'conditions': [{
        'display_name': 'test condition',
        'condition_threshold': {
            'filter': f'metric.type = "{METRIC_PATH}" AND resource.type = "{RESOURCE_TYPE}"',
            'comparison': 'COMPARISON_GT',
            'threshold_value': TRIGGER_NOTIFICATION_THRESHOLD_DOUBLE,
            'duration': Duration(seconds=0),
        }
    }],
    'notification_channels': []
}

TEST_SERIES = {
    'metric': {
        'type': METRIC_PATH,
    },
    'resource': {
        'type': RESOURCE_TYPE,
        'labels': {
            'instance_id': INSTANCE_ID,
            'zone': ZONE
        }
    }
}<|endoftext|>


<commit_before># Copyright (c) 2016 Cisco Systems, Inc.
# All Rights Reserved.
#
#    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 eventlet.queue
from oslo_config import cfg
from oslo_log import log as logging
import requests
import threading

from neutron.common import constants as n_const
from neutron import context as n_context
from neutron.extensions import portbindings
from neutron import manager
from neutron.plugins.common import constants as p_constants
from neutron.plugins.ml2 import driver_api as api
from neutron_lib import constants as nl_const

LOG = logging.getLogger(__name__)

vpp_opts = [
    cfg.StrOpt('agents',
               help=_("HTTP URLs of agents on compute nodes.")),
]

cfg.CONF.register_opts(vpp_opts, "ml2_vpp")

class VPPMechanismDriver(api.MechanismDriver):
    supported_vnic_types = [portbindings.VNIC_NORMAL]
    allowed_network_types = [p_constants.TYPE_VLAN,p_constants.TYPE_VXLAN]
    MECH_NAME = 'vpp'

    # TODO(ijw): we have no agent registration because we're not using
    # Neutron style agents, so at the moment we make up one physical net
    # that all 'agents' are assumed to know.
    physical_networks = ['physnet']

    def initialize(self):
        self.communicator = AgentCommunicator()

    def bind_port(self, port_context):
        """Attempt to bind a port.

        :param port_context: PortContext instance describing the port

        This method is called outside any transaction to attempt to
        establish a port binding using this mechanism driver. Bindings
        may be created at each of multiple levels of a hierarchical
        network, and are established from the top level downward. At
        each level, the mechanism driver determines whether it can
        bind to any of the network segments in the
        port_context.segments_to_bind property, based on the value of the
        port_context.host property, any relevant port or network
        attributes, and its own knowledge of the network topology. At
        the top level, port_context.segments_to_bind contains the static
        segments of the port's network. At each lower level of
        binding, it contains static or dynamic segments supplied by
        the driver that bound at the level above. If the driver is
        able to complete the binding of the port to any segment in
        port_context.segments_to_bind, it must call port_context.set_binding
        with the binding details. If it can partially bind the port,
        it must call port_context.continue_binding with the network
        segments to be used to bind at the next lower level.

        If the binding results are committed after bind_port returns,
        they will be seen by all mechanism drivers as
        update_port_precommit and update_port_postcommit calls. But if
        some other thread or process concurrently binds or updates the
        port, these binding results will not be committed, and
        update_port_precommit and update_port_postcommit will not be
        called on the mechanism drivers with these results. Because
        binding results can be discarded rather than committed,
        drivers should avoid making persistent state changes in
        bind_port, or else must ensure that such state changes are
        eventually cleaned up.

        Implementing this method explicitly declares the mechanism
        driver as having the intention to bind ports. This is inspected
        by the QoS service to identify the available QoS rules you
        can use with ports.
        """
        LOG.debug("ML2_VPP: Attempting to bind port %(port)s on "
                  "network %(network)s",
                  {'port': port_context.current['id'],
                   'network': port_context.network.current['id']})
        vnic_type = port_context.current.get(portbindings.VNIC_TYPE,
                                             portbindings.VNIC_NORMAL)
        if vnic_type not in self.supported_vnic_types:
            LOG.debug("ML2_VPP: Refusing to bind due to unsupported vnic_type: %s",
                      vnic_type)
            return

        for segment in port_context.segments_to_bind:
            if self.check_segment(segment, port_context.host):
                vif_details = dict(self.vif_details)
                # TODO(ijw) should be in a library that the agent uses
                vif_details['vhostuser_socket'] = \
                    '/tmp/%s' % port_context.current['id']
                vif_details['vhostuser_mode'] = \
                    'client'
                LOG.debug('ML2_VPP: Setting details: %s', vif_details)
                port_context.set_binding(segment[api.ID],
                                         self.vif_type,
                                         vif_details)
                LOG.debug("ML2_VPP: Bound using segment: %s", segment)
                return

    # TODO(ijw) should be pulled from a constants file
    vif_type = 'vhostuser'
    vif_details = {}

    def check_segment(self, segment, host):
        """Check if segment can be bound.

        :param segment: segment dictionary describing segment to bind
        :param host: host on which the segment must be bound to a port
        :returns: True iff segment can be bound for host

        """

        # TODO(ijw): naive - doesn't check host, or configured
        # physnets on the host.  Should work out if the binding
        # can't be achieved before accepting it

        network_type = segment[api.NETWORK_TYPE]
        if network_type not in self.allowed_network_types:
            LOG.debug(
                'ML2_VPP: Network %(network_id)s is %(network_type)s, but this driver '
                'only supports types %(allowed_network_types)s.  The type '
                'must be supported  if binding is to succeed.',
                {'network_id': segment['id'],
                 'network_type': network_type,
                 'allowed_network_types':
                 ', '.join(self.allowed_network_types)}
            )
            return False

        if network_type in [p_constants.TYPE_FLAT, p_constants.TYPE_VLAN]:
            physnet = segment[api.PHYSICAL_NETWORK]
            if not self.physnet_known(physnet):
                LOG.debug(
                    'ML2_VPP: Network %(network_id)s is connected to physical '
                    'network %(physnet)s, but the physical network '
                    'is not one this mechdriver knows.  The physical network '
                    'must be known if binding is to succeed.',
                    {'network_id': segment['id'],
                     'physnet': physnet}
                )
                return False

        return True

    def physnet_known(self, physnet):
        return physnet in self.physical_networks

    def check_vlan_transparency(self, port_context):
        """Check if the network supports vlan transparency.

        :param port_context: NetworkContext instance describing the network.

        In general we do not support VLAN transparency (yet).
        """
        return False

    def update_port_postcommit(self, port_context):
        """Work to do, post-DB commit, when updating a port

        After accepting an update_port, determine if we have any work to do
        on the network devices.
        """
        # TODO(ijw): optimisation: the update port may leave the
        # binding state the same as before if someone updated
        # something other than the binding on the port, but this
        # way we always send it out and it's the far end's job to
        # ignore it.  Doing less work is nevertheless good, so we
        # should in future avoid the send.

        LOG.debug('ML2_VPP: update_port_postcommit, port is %s' % str(port_context.current))

        if port_context.binding_levels is not None:
            current_bind = port_context.binding_levels[-1]
            if port_context.original_binding_levels is None:
                prev_bind = None
            else:
                prev_bind = port_context.original_binding_levels[-1]

            # We have to explicitly avoid binding agent ports - DHCP,
            # L3 etc. - as vhostuser. The interface code below takes
            # care of those.

            bind_type = 'vhostuser'

            owner = port_context.current['device_owner']

            # Neutron really ought to tell us what port type it thinks
            # is sensible, but it leaves us to make an educated guess.
            LOG.error('testing owner %s against (%s)'
                      % (owner, ' '.join(nl_const.DEVICE_OWNER_PREFIXES)))
            for f in nl_const.DEVICE_OWNER_PREFIXES:
                if owner.startswith(f):
                    bind_type = 'plugtap'

            LOG.error('binding to with type %s' % bind_type)

            if (current_bind is not None and
               current_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # then send the bind out (may equally be an update on a bound
                # port)
                LOG.debug("ML2-VPP: Sending bind request to agent communicator for port %(port)s"
                          "segment %(segment)s, host %(host)s, type %(bind_type)s",
                          {
                          'port': port_context.current,
                          'segment': current_bind[api.BOUND_SEGMENT],
                          'host': port_context.host,
                          'bind_type': bind_type
                          }
                         )
                self.communicator.bind(port_context.current,
                                       current_bind[api.BOUND_SEGMENT],
                                       port_context.host,
                                       bind_type)
            elif (prev_bind is not None and
                  prev_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # If we were the last binder of this port but are no longer
                LOG.debug("ML2_VPP: Sending unbind request to agent communicator for port %(port)s"
                          "on host %(host)s",
                          {
                          'port': port_context.current,
                          'host': port_context.original_host,
                          }
                         )
                self.communicator.unbind(port_context.current,
                                         port_context.original_host)

class AgentCommunicator(object):
    def __init__(self):
        if cfg.CONF.ml2_vpp.agents is None:
            LOG.error('ML2_VPP: needs agents configured right now')
        self.agents = cfg.CONF.ml2_vpp.agents.split(',')
        LOG.debug("ML2_VPP: Configured agents are: %s " % str(self.agents))
        self.recursive = False
        self.queue = eventlet.queue.Queue()
        self.sync_thread = threading.Thread(
            name='vpp-sync',
            target=self._worker)
        self.sync_thread.start()

    def _worker(self):
        while True:
            msg = self.queue.get()
            op = msg[0]
            args = msg[1:]
            if op == 'bind':
                self.send_bind(*args)
            elif op == 'unbind':
                self.send_unbind(*args)
            else:
                LOG.error('ML2_VPP: unknown queue op %s' % str(op))

    def bind(self, port, segment, host, bind_type):
        """Queue up a bind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """

        LOG.debug("ML2_VPP: Queing bind request for port:%(port)s, segment:%(segment)s"
                  "on host:%(host)s, type:%(type)s",
                  {
                  'port': port, 'segment': segment,
                  'host': host, 'type': bind_type
                  } )
        self.queue.put(['bind', port, segment, host, bind_type])

    def unbind(self, port, host):
        """Queue up an unbind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """

        LOG.debug("ML2_VPP: Queing unbind request for port:%(port)s,"
                  "on host:%(host)s,",
                  {
                  'port': port,
                  'host': host
                  } )
        self.queue.put(['unbind', port, host])

    def send_bind(self, port, segment, host, type):
        data = {
            'host': host,
            'mac_address': port['mac_address'],
            'mtu': 1500,  # not this, but what?: port['mtu'],
            'network_type': segment[api.NETWORK_TYPE],
            'segmentation_id': segment[api.SEGMENTATION_ID],
            'bind_type': type
        }
        self._broadcast_msg('ports/%s/bind' % port['id'], data)

        # This should only be sent when we're certain that the port
        # is bound If this is in a bg thread, it should be sent there,
        # and it should only go when we have confirmed that the far end
        # has done its work.  The VM will start when it's called and
        # will wait until then.  For us this is useful beyond the usual
        # reasons of deplying the VM start until DHCP can be reached,
        # because we know the server socket is in place for the port.

        context = n_context.get_admin_context()
        plugin = manager.NeutronManager.get_plugin()
        # Bodge
        if self.recursive:
<<<<<<< 27f73f99c9a745c65e4184b8bcfd8697eca7e35b
            # This happens right now because when we update the port
            # status, we update the port and the update notification
            # comes through to here.
            # TODO(ijw) wants a more permanent fix, because this only
            # happens due to the threading model.  We should be
            # spotting relevant changes in postcommit.
            LOG.warning('Your recursion check hit on activating port')
=======
            LOG.warning('ML2_VPP: Your recursion check hit on activating port')
>>>>>>> add mech_vpp debugs
        else:
            self.recursive = True
            plugin.update_port_status(context, port['id'],
                                      n_const.PORT_STATUS_ACTIVE,
                                      host=host)
            self.recursive = False

    def send_unbind(self, port, host):
        data = {}
        self._broadcast_msg('ports/%s/unbind/%s' % (port['id'], host),
                            data)

    def _broadcast_msg(self, urlfrag, msg):
        # TODO(ijw): since we pretty much always know the host to which the
        # port is being bound or unbound, there's absolutely no reason
        # to broadcast this, but right now this saves us config work.
        # In a small cloud with not too many ports the workload on the
        # agents is not onerous.
        for url in self.agents:
            LOG.debug("ML2_VPP: Sending message: %s to agent: %s" % (msg, url + urlfrag))
            requests.put(url + urlfrag, data=msg)
<commit_msg>update agent list in devstack settings<commit_after># Copyright (c) 2016 Cisco Systems, Inc.
# All Rights Reserved.
#
#    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 eventlet.queue
from oslo_config import cfg
from oslo_log import log as logging
import requests
import threading

from neutron.common import constants as n_const
from neutron import context as n_context
from neutron.extensions import portbindings
from neutron import manager
from neutron.plugins.common import constants as p_constants
from neutron.plugins.ml2 import driver_api as api
from neutron_lib import constants as nl_const

LOG = logging.getLogger(__name__)

vpp_opts = [
    cfg.StrOpt('agents',
               help=_("HTTP URLs of agents on compute nodes.")),
]

cfg.CONF.register_opts(vpp_opts, "ml2_vpp")

class VPPMechanismDriver(api.MechanismDriver):
    supported_vnic_types = [portbindings.VNIC_NORMAL]
    allowed_network_types = [p_constants.TYPE_VLAN,p_constants.TYPE_VXLAN]
    MECH_NAME = 'vpp'

    # TODO(ijw): we have no agent registration because we're not using
    # Neutron style agents, so at the moment we make up one physical net
    # that all 'agents' are assumed to know.
    physical_networks = ['physnet']

    def initialize(self):
        self.communicator = AgentCommunicator()

    def bind_port(self, port_context):
        """Attempt to bind a port.

        :param port_context: PortContext instance describing the port

        This method is called outside any transaction to attempt to
        establish a port binding using this mechanism driver. Bindings
        may be created at each of multiple levels of a hierarchical
        network, and are established from the top level downward. At
        each level, the mechanism driver determines whether it can
        bind to any of the network segments in the
        port_context.segments_to_bind property, based on the value of the
        port_context.host property, any relevant port or network
        attributes, and its own knowledge of the network topology. At
        the top level, port_context.segments_to_bind contains the static
        segments of the port's network. At each lower level of
        binding, it contains static or dynamic segments supplied by
        the driver that bound at the level above. If the driver is
        able to complete the binding of the port to any segment in
        port_context.segments_to_bind, it must call port_context.set_binding
        with the binding details. If it can partially bind the port,
        it must call port_context.continue_binding with the network
        segments to be used to bind at the next lower level.

        If the binding results are committed after bind_port returns,
        they will be seen by all mechanism drivers as
        update_port_precommit and update_port_postcommit calls. But if
        some other thread or process concurrently binds or updates the
        port, these binding results will not be committed, and
        update_port_precommit and update_port_postcommit will not be
        called on the mechanism drivers with these results. Because
        binding results can be discarded rather than committed,
        drivers should avoid making persistent state changes in
        bind_port, or else must ensure that such state changes are
        eventually cleaned up.

        Implementing this method explicitly declares the mechanism
        driver as having the intention to bind ports. This is inspected
        by the QoS service to identify the available QoS rules you
        can use with ports.
        """
        LOG.debug("ML2_VPP: Attempting to bind port %(port)s on "
                  "network %(network)s",
                  {'port': port_context.current['id'],
                   'network': port_context.network.current['id']})
        vnic_type = port_context.current.get(portbindings.VNIC_TYPE,
                                             portbindings.VNIC_NORMAL)
        if vnic_type not in self.supported_vnic_types:
            LOG.debug("ML2_VPP: Refusing to bind due to unsupported vnic_type: %s",
                      vnic_type)
            return

        for segment in port_context.segments_to_bind:
            if self.check_segment(segment, port_context.host):
                vif_details = dict(self.vif_details)
                # TODO(ijw) should be in a library that the agent uses
                vif_details['vhostuser_socket'] = \
                    '/tmp/%s' % port_context.current['id']
                vif_details['vhostuser_mode'] = \
                    'client'
                LOG.debug('ML2_VPP: Setting details: %s', vif_details)
                port_context.set_binding(segment[api.ID],
                                         self.vif_type,
                                         vif_details)
                LOG.debug("ML2_VPP: Bound using segment: %s", segment)
                return

    # TODO(ijw) should be pulled from a constants file
    vif_type = 'vhostuser'
    vif_details = {}

    def check_segment(self, segment, host):
        """Check if segment can be bound.

        :param segment: segment dictionary describing segment to bind
        :param host: host on which the segment must be bound to a port
        :returns: True iff segment can be bound for host

        """

        # TODO(ijw): naive - doesn't check host, or configured
        # physnets on the host.  Should work out if the binding
        # can't be achieved before accepting it

        network_type = segment[api.NETWORK_TYPE]
        if network_type not in self.allowed_network_types:
            LOG.debug(
                'ML2_VPP: Network %(network_id)s is %(network_type)s, but this driver '
                'only supports types %(allowed_network_types)s.  The type '
                'must be supported  if binding is to succeed.',
                {'network_id': segment['id'],
                 'network_type': network_type,
                 'allowed_network_types':
                 ', '.join(self.allowed_network_types)}
            )
            return False

        if network_type in [p_constants.TYPE_FLAT, p_constants.TYPE_VLAN]:
            physnet = segment[api.PHYSICAL_NETWORK]
            if not self.physnet_known(physnet):
                LOG.debug(
                    'ML2_VPP: Network %(network_id)s is connected to physical '
                    'network %(physnet)s, but the physical network '
                    'is not one this mechdriver knows.  The physical network '
                    'must be known if binding is to succeed.',
                    {'network_id': segment['id'],
                     'physnet': physnet}
                )
                return False

        return True

    def physnet_known(self, physnet):
        return physnet in self.physical_networks

    def check_vlan_transparency(self, port_context):
        """Check if the network supports vlan transparency.

        :param port_context: NetworkContext instance describing the network.

        In general we do not support VLAN transparency (yet).
        """
        return False

    def update_port_postcommit(self, port_context):
        """Work to do, post-DB commit, when updating a port

        After accepting an update_port, determine if we have any work to do
        on the network devices.
        """
        # TODO(ijw): optimisation: the update port may leave the
        # binding state the same as before if someone updated
        # something other than the binding on the port, but this
        # way we always send it out and it's the far end's job to
        # ignore it.  Doing less work is nevertheless good, so we
        # should in future avoid the send.

        LOG.debug('ML2_VPP: update_port_postcommit, port is %s' % str(port_context.current))

        if port_context.binding_levels is not None:
            current_bind = port_context.binding_levels[-1]
            if port_context.original_binding_levels is None:
                prev_bind = None
            else:
                prev_bind = port_context.original_binding_levels[-1]

            # We have to explicitly avoid binding agent ports - DHCP,
            # L3 etc. - as vhostuser. The interface code below takes
            # care of those.

            bind_type = 'vhostuser'

            owner = port_context.current['device_owner']

            # Neutron really ought to tell us what port type it thinks
            # is sensible, but it leaves us to make an educated guess.
            LOG.error('testing owner %s against (%s)'
                      % (owner, ' '.join(nl_const.DEVICE_OWNER_PREFIXES)))
            for f in nl_const.DEVICE_OWNER_PREFIXES:
                if owner.startswith(f):
                    bind_type = 'plugtap'

            LOG.error('binding to with type %s' % bind_type)

            if (current_bind is not None and
               current_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # then send the bind out (may equally be an update on a bound
                # port)
                LOG.debug("ML2-VPP: Sending bind request to agent communicator for port %(port)s"
                          "segment %(segment)s, host %(host)s, type %(bind_type)s",
                          {
                          'port': port_context.current,
                          'segment': current_bind[api.BOUND_SEGMENT],
                          'host': port_context.host,
                          'bind_type': bind_type
                          }
                         )
                self.communicator.bind(port_context.current,
                                       current_bind[api.BOUND_SEGMENT],
                                       port_context.host,
                                       bind_type)
            elif (prev_bind is not None and
                  prev_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # If we were the last binder of this port but are no longer
                LOG.debug("ML2_VPP: Sending unbind request to agent communicator for port %(port)s"
                          "on host %(host)s",
                          {
                          'port': port_context.current,
                          'host': port_context.original_host,
                          }
                         )
                self.communicator.unbind(port_context.current,
                                         port_context.original_host)

class AgentCommunicator(object):
    def __init__(self):
        if cfg.CONF.ml2_vpp.agents is None:
            LOG.error('ML2_VPP: needs agents configured right now')
        self.agents = cfg.CONF.ml2_vpp.agents.split(',')
        LOG.debug("ML2_VPP: Configured agents are: %s " % str(self.agents))
        self.recursive = False
        self.queue = eventlet.queue.Queue()
        self.sync_thread = threading.Thread(
            name='vpp-sync',
            target=self._worker)
        self.sync_thread.start()

    def _worker(self):
        while True:
            msg = self.queue.get()
            op = msg[0]
            args = msg[1:]
            if op == 'bind':
                self.send_bind(*args)
            elif op == 'unbind':
                self.send_unbind(*args)
            else:
                LOG.error('ML2_VPP: unknown queue op %s' % str(op))

    def bind(self, port, segment, host, bind_type):
        """Queue up a bind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """

        LOG.debug("ML2_VPP: Queing bind request for port:%(port)s, segment:%(segment)s"
                  "on host:%(host)s, type:%(type)s",
                  {
                  'port': port, 'segment': segment,
                  'host': host, 'type': bind_type
                  } )
        self.queue.put(['bind', port, segment, host, bind_type])

    def unbind(self, port, host):
        """Queue up an unbind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """

        LOG.debug("ML2_VPP: Queing unbind request for port:%(port)s,"
                  "on host:%(host)s,",
                  {
                  'port': port,
                  'host': host
                  } )
        self.queue.put(['unbind', port, host])

    def send_bind(self, port, segment, host, type):
        data = {
            'host': host,
            'mac_address': port['mac_address'],
            'mtu': 1500,  # not this, but what?: port['mtu'],
            'network_type': segment[api.NETWORK_TYPE],
            'segmentation_id': segment[api.SEGMENTATION_ID],
            'bind_type': type
        }
        self._unicast_msg('ports/%s/bind' % port['id'], data)

        # This should only be sent when we're certain that the port
        # is bound If this is in a bg thread, it should be sent there,
        # and it should only go when we have confirmed that the far end
        # has done its work.  The VM will start when it's called and
        # will wait until then.  For us this is useful beyond the usual
        # reasons of deplying the VM start until DHCP can be reached,
        # because we know the server socket is in place for the port.

        context = n_context.get_admin_context()
        plugin = manager.NeutronManager.get_plugin()
        # Bodge
        if self.recursive:
<<<<<<< 27f73f99c9a745c65e4184b8bcfd8697eca7e35b
            # This happens right now because when we update the port
            # status, we update the port and the update notification
            # comes through to here.
            # TODO(ijw) wants a more permanent fix, because this only
            # happens due to the threading model.  We should be
            # spotting relevant changes in postcommit.
            LOG.warning('Your recursion check hit on activating port')
=======
            LOG.warning('ML2_VPP: Your recursion check hit on activating port')
>>>>>>> add mech_vpp debugs
        else:
            self.recursive = True
            plugin.update_port_status(context, port['id'],
                                      n_const.PORT_STATUS_ACTIVE,
                                      host=host)
            self.recursive = False

    def send_unbind(self, port, host):
        data = {}
        self._unicast_msg('ports/%s/unbind/%s' % (port['id'], host),
                            data)

    def _unicast_msg(self, urlfrag, msg):
        # Send unicast message to the agent on the host
        for url in self.agents:
            LOG.debug("ML2_VPP: Sending message: %s to agent: %s" % (msg, url + urlfrag))
            requests.put(url + urlfrag, data=msg)
<|endoftext|>


<commit_before>"""
Implements an XMLRPC dispatcher
"""

try:
    # Python2
    from xmlrpclib import Fault, dumps
    from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
except ImportError:
    # Python3
    from xmlrpc.client import Fault, dumps
    from xmlrpc.server import SimpleXMLRPCDispatcher

from defusedxml import xmlrpc

# This method makes the XMLRPC parser (used by loads) safe
# from various XML based attacks
xmlrpc.monkey_patch()

class XMLRPCDispatcher(SimpleXMLRPCDispatcher):
    """
    Encodes and decodes XMLRPC messages, dispatches to the requested method
    and returns any responses or errors in encoded XML.

    Subclasses SimpleXMLRPCDispatcher so that it can
    also pass the Django HttpRequest object from the underlying RPC request
    """

    def __init__(self):
        self.funcs = {}
        self.instance = None
        self.allow_none = True
        self.encoding = None

    def dispatch(self, data, **kwargs):
        """
        Extracts the xml marshaled parameters and method name and calls the
        underlying method and returns either an xml marshaled response
        or an XMLRPC fault

        Although very similar to the superclass' _marshaled_dispatch, this
        method has a different name due to the different parameters it takes
        from the superclass method.
        """

        try:
            params, method = xmlrpc.xmlrpc_client.loads(data)

            try:
                response = self._dispatch(method, params, **kwargs)
            except TypeError:
                # Catch unexpected keyword argument error
                response = self._dispatch(method, params)

            # wrap response in a singleton tuple
            response = (response,)
            response = dumps(response, methodresponse=1,
                             allow_none=self.allow_none,
                             encoding=self.encoding)
        except Fault as fault:
            response = dumps(fault, allow_none=self.allow_none,
                             encoding=self.encoding)
        except Exception:
            response = dumps(
                Fault(1, 'Unknown error'),
                encoding=self.encoding, allow_none=self.allow_none,
            )

        return response

    def _dispatch(self, method, params, **kwargs):
        """
        Dispatches the method with the parameters to the underlying method
        """

        func = self.funcs.get(method, None)

        if func is not None:
            if len(kwargs) > 0:
                return func(*params, **kwargs)
            else:
                return func(*params)
        else:
            raise Exception('method "%s" is not supported' % method)
<commit_msg>clean way to provide request argument<commit_after>"""
Implements an XMLRPC dispatcher
"""

try:
    # Python2
    from xmlrpclib import Fault, dumps
    from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
except ImportError:
    # Python3
    from xmlrpc.client import Fault, dumps
    from xmlrpc.server import SimpleXMLRPCDispatcher

import inspect
from defusedxml import xmlrpc

# This method makes the XMLRPC parser (used by loads) safe
# from various XML based attacks
xmlrpc.monkey_patch()

class XMLRPCDispatcher(SimpleXMLRPCDispatcher):
    """
    Encodes and decodes XMLRPC messages, dispatches to the requested method
    and returns any responses or errors in encoded XML.

    Subclasses SimpleXMLRPCDispatcher so that it can
    also pass the Django HttpRequest object from the underlying RPC request
    """

    def __init__(self):
        self.funcs = {}
        self.instance = None
        self.allow_none = True
        self.encoding = None

    def dispatch(self, data, **kwargs):
        """
        Extracts the xml marshaled parameters and method name and calls the
        underlying method and returns either an xml marshaled response
        or an XMLRPC fault

        Although very similar to the superclass' _marshaled_dispatch, this
        method has a different name due to the different parameters it takes
        from the superclass method.
        """

        try:
            params, method = xmlrpc.xmlrpc_client.loads(data)

            try:
                response = self._dispatch(method, params, **kwargs)
            except TypeError:
                # Catch unexpected keyword argument error
                response = self._dispatch(method, params)

            # wrap response in a singleton tuple
            response = (response,)
            response = dumps(response, methodresponse=1,
                             allow_none=self.allow_none,
                             encoding=self.encoding)
        except Fault as fault:
            response = dumps(fault, allow_none=self.allow_none,
                             encoding=self.encoding)
        except Exception:
            response = dumps(
                Fault(1, 'Unknown error'),
                encoding=self.encoding, allow_none=self.allow_none,
            )

        return response

    def _dispatch(self, method, params, **kwargs):
        """
        Dispatches the method with the parameters to the underlying method
        """

        func = self.funcs.get(method, None)

        #add some magic
        #if request is the first arg of func and request is provided in kwargs we inject it
        if 'request' in kwargs and inspect.getargspec(func)[0][0] == 'request':
            request = kwargs.pop('request')
            params = (request,) + params

        if func is not None:
            if len(kwargs) > 0:
                return func(*params, **kwargs)
            else:
                return func(*params)
        else:
            raise Exception('method "%s" is not supported' % method)
<|endoftext|>


<commit_before>from base64 import b64decode, b64encode
from collections import Sequence

from django.db.models import Field, Func, Value, TextField
from django.utils.translation import ugettext_lazy as _

class TupleField(Field):
    pass

class Tuple(Func):
    function = ''
    output_field = TupleField()

    def get_group_by_cols(self):
        # Irrespective of whether we have an aggregate, we want to drill down
        # to the children here. You can't GROUP BY a tuple like you would for a
        # "normal" function - i.e. GROUP BY ("a", "b") is invalid SQL. However,
        # it's logically equivalent to GROUP BY "a", "b" in call cases, so we
        # never need the case where this 'function' needs to be included in the
        # clause.
        cols = []
        for expr in self.source_expressions:
            cols += expr.get_group_by_cols()
        return cols

class InvalidCursor(Exception):
    pass

def reverse_ordering(ordering_tuple):
    """
    Given an order_by tuple such as `('-created', 'uuid')` reverse the
    ordering and return a new tuple, eg. `('created', '-uuid')`.
    """
    def invert(x):
        return x[1:] if (x.startswith('-')) else '-' + x

    return tuple([invert(item) for item in ordering_tuple])

class CursorPage(Sequence):
    def __init__(self, items, paginator, has_next=False, has_previous=False):
        self.items = items
        self.paginator = paginator
        self.has_next = has_next
        self.has_previous = has_previous

    def __len__(self):
        return len(self.items)

    def __getitem__(self, key):
        return self.items.__getitem__(key)

    def __repr__(self):
        return '<Page: [%s%s]>' % (', '.join(repr(i) for i in self.items[:21]), ' (remaining truncated)' if len(self.items) > 21 else '')

class CursorPaginator(object):
    delimiter = '|'
    invalid_cursor_message = _('Invalid cursor')

    def __init__(self, queryset, ordering):
        self.queryset = queryset.order_by(*ordering)
        self.ordering = ordering

        if not all(o.startswith('-') for o in ordering) and not all(not o.startswith('-') for o in ordering):
            raise InvalidCursor('Direction of orderings must match')

    def page(self, first=None, last=None, after=None, before=None):
        qs = self.queryset
        page_size = first or last
        if page_size is None:
            return CursorPage(qs, self)

        if after is not None:
            qs = self.apply_cursor(after, qs)
        if before is not None:
            qs = self.apply_cursor(before, qs, reverse=True)
        if first is not None:
            qs = qs[:first + 1]
        if last is not None:
            if first is not None:
                raise ValueError('Cannot process first and last')
            qs = qs.order_by(*reverse_ordering(self.ordering))[:last + 1]

        qs = list(qs)
        items = qs[:page_size]
        if last is not None:
            items.reverse()
        has_additional = len(qs) > len(items)
        additional_kwargs = {}
        if first is not None:
            additional_kwargs['has_next'] = has_additional
            additional_kwargs['has_previous'] = bool(after)
        elif last is not None:
            additional_kwargs['has_previous'] = has_additional
            additional_kwargs['has_next'] = bool(before)
        return CursorPage(items, self, **additional_kwargs)

    def apply_cursor(self, cursor, queryset, reverse=False):
        position = self.decode_cursor(cursor)

        is_reversed = self.ordering[0].startswith('-')
        queryset = queryset.annotate(_cursor=Tuple(*[o.lstrip('-') for o in self.ordering]))
        current_position = [Value(p, output_field=TextField()) for p in position]
        if reverse != is_reversed:
            return queryset.filter(_cursor__lt=Tuple(*current_position))
        return queryset.filter(_cursor__gt=Tuple(*current_position))

    def decode_cursor(self, cursor):
        try:
            orderings = b64decode(cursor.encode('ascii')).decode('utf8')
            return orderings.split(self.delimiter)
        except (TypeError, ValueError):
            raise InvalidCursor(self.invalid_cursor_message)

    def encode_cursor(self, position):
        encoded = b64encode(self.delimiter.join(position).encode('utf8')).decode('ascii')
        return encoded

    def position_from_instance(self, instance):
        position = []
        for order in self.ordering:
            parts = order.lstrip('-').split('__')
            attr = instance
            while parts:
                attr = getattr(attr, parts[0])
                parts.pop(0)
            position.append(str(attr))
        return position

    def cursor(self, instance):
        return self.encode_cursor(self.position_from_instance(instance))
<commit_msg>Replace gettext_lazy with ugettext_lazy <commit_after>from base64 import b64decode, b64encode
from collections import Sequence

from django.db.models import Field, Func, Value, TextField
from django.utils.translation import gettext_lazy as _

class TupleField(Field):
    pass

class Tuple(Func):
    function = ''
    output_field = TupleField()

    def get_group_by_cols(self):
        # Irrespective of whether we have an aggregate, we want to drill down
        # to the children here. You can't GROUP BY a tuple like you would for a
        # "normal" function - i.e. GROUP BY ("a", "b") is invalid SQL. However,
        # it's logically equivalent to GROUP BY "a", "b" in call cases, so we
        # never need the case where this 'function' needs to be included in the
        # clause.
        cols = []
        for expr in self.source_expressions:
            cols += expr.get_group_by_cols()
        return cols

class InvalidCursor(Exception):
    pass

def reverse_ordering(ordering_tuple):
    """
    Given an order_by tuple such as `('-created', 'uuid')` reverse the
    ordering and return a new tuple, eg. `('created', '-uuid')`.
    """
    def invert(x):
        return x[1:] if (x.startswith('-')) else '-' + x

    return tuple([invert(item) for item in ordering_tuple])

class CursorPage(Sequence):
    def __init__(self, items, paginator, has_next=False, has_previous=False):
        self.items = items
        self.paginator = paginator
        self.has_next = has_next
        self.has_previous = has_previous

    def __len__(self):
        return len(self.items)

    def __getitem__(self, key):
        return self.items.__getitem__(key)

    def __repr__(self):
        return '<Page: [%s%s]>' % (', '.join(repr(i) for i in self.items[:21]), ' (remaining truncated)' if len(self.items) > 21 else '')

class CursorPaginator(object):
    delimiter = '|'
    invalid_cursor_message = _('Invalid cursor')

    def __init__(self, queryset, ordering):
        self.queryset = queryset.order_by(*ordering)
        self.ordering = ordering

        if not all(o.startswith('-') for o in ordering) and not all(not o.startswith('-') for o in ordering):
            raise InvalidCursor('Direction of orderings must match')

    def page(self, first=None, last=None, after=None, before=None):
        qs = self.queryset
        page_size = first or last
        if page_size is None:
            return CursorPage(qs, self)

        if after is not None:
            qs = self.apply_cursor(after, qs)
        if before is not None:
            qs = self.apply_cursor(before, qs, reverse=True)
        if first is not None:
            qs = qs[:first + 1]
        if last is not None:
            if first is not None:
                raise ValueError('Cannot process first and last')
            qs = qs.order_by(*reverse_ordering(self.ordering))[:last + 1]

        qs = list(qs)
        items = qs[:page_size]
        if last is not None:
            items.reverse()
        has_additional = len(qs) > len(items)
        additional_kwargs = {}
        if first is not None:
            additional_kwargs['has_next'] = has_additional
            additional_kwargs['has_previous'] = bool(after)
        elif last is not None:
            additional_kwargs['has_previous'] = has_additional
            additional_kwargs['has_next'] = bool(before)
        return CursorPage(items, self, **additional_kwargs)

    def apply_cursor(self, cursor, queryset, reverse=False):
        position = self.decode_cursor(cursor)

        is_reversed = self.ordering[0].startswith('-')
        queryset = queryset.annotate(_cursor=Tuple(*[o.lstrip('-') for o in self.ordering]))
        current_position = [Value(p, output_field=TextField()) for p in position]
        if reverse != is_reversed:
            return queryset.filter(_cursor__lt=Tuple(*current_position))
        return queryset.filter(_cursor__gt=Tuple(*current_position))

    def decode_cursor(self, cursor):
        try:
            orderings = b64decode(cursor.encode('ascii')).decode('utf8')
            return orderings.split(self.delimiter)
        except (TypeError, ValueError):
            raise InvalidCursor(self.invalid_cursor_message)

    def encode_cursor(self, position):
        encoded = b64encode(self.delimiter.join(position).encode('utf8')).decode('ascii')
        return encoded

    def position_from_instance(self, instance):
        position = []
        for order in self.ordering:
            parts = order.lstrip('-').split('__')
            attr = instance
            while parts:
                attr = getattr(attr, parts[0])
                parts.pop(0)
            position.append(str(attr))
        return position

    def cursor(self, instance):
        return self.encode_cursor(self.position_from_instance(instance))
<|endoftext|>