def create_endpoint(port=None, service_name=None, host=None, use_defaults=True):
    """Creates a new Endpoint object.

    :param port: TCP/UDP port. Defaults to 0.
    :type port: int
    :param service_name: service name as a str. Defaults to 'unknown'.
    :type service_name: str
    :param host: ipv4 or ipv6 address of the host. Defaults to the
    current host ip.
    :type host: str
    :param use_defaults: whether to use defaults.
    :type use_defaults: bool
    :returns: zipkin Endpoint object
    """
    if use_defaults:
        if port is None:
            port = 0
        if service_name is None:
            service_name = 'unknown'
        if host is None:
            try:
                host = socket.gethostbyname(socket.gethostname())
            except socket.gaierror:
                host = '127.0.0.1'

    ipv4 = None
    ipv6 = None

    if host:
        # Check ipv4 or ipv6.
        try:
            socket.inet_pton(socket.AF_INET, host)
            ipv4 = host
        except socket.error:
            # If it's not an ipv4 address, maybe it's ipv6.
            try:
                socket.inet_pton(socket.AF_INET6, host)
                ipv6 = host
            except socket.error:
                # If it's neither ipv4 or ipv6, leave both ip addresses unset.
                pass

    return Endpoint(
        ipv4=ipv4,
        ipv6=ipv6,
        port=port,
        service_name=service_name,
    )


def copy_endpoint_with_new_service_name(endpoint, new_service_name):
    """Creates a copy of a given endpoint with a new service name.

    :param endpoint: existing Endpoint object
    :type endpoint: Endpoint
    :param new_service_name: new service name
    :type new_service_name: str
    :returns: zipkin new Endpoint object
    """
    return Endpoint(
        service_name=new_service_name,
        ipv4=endpoint.ipv4,
        ipv6=endpoint.ipv6,
        port=endpoint.port,
    )

def copy_endpoint_with_new_service_name ( endpoint , new_service_name ) : return Endpoint ( service_name = new_service_name , ipv4 = endpoint . ipv4 , ipv6 = endpoint . ipv6 , port = endpoint . port , )

Creates a copy of a given endpoint with a new service name .


def build_v1_span(self):
        """Builds and returns a V1 Span.

        :return: newly generated _V1Span
        :rtype: _V1Span
        """
        # We are simulating a full two-part span locally, so set cs=sr and ss=cr
        full_annotations = OrderedDict([
            ('cs', self.timestamp),
            ('sr', self.timestamp),
            ('ss', self.timestamp + self.duration),
            ('cr', self.timestamp + self.duration),
        ])

        if self.kind != Kind.LOCAL:
            # If kind is not LOCAL, then we only want client or
            # server side annotations.
            for ann in _DROP_ANNOTATIONS_BY_KIND[self.kind]:
                del full_annotations[ann]

        # Add user-defined annotations. We write them in full_annotations
        # instead of the opposite so that user annotations will override
        # any automatically generated annotation.
        full_annotations.update(self.annotations)

        return _V1Span(
            trace_id=self.trace_id,
            name=self.name,
            parent_id=self.parent_id,
            id=self.span_id,
            timestamp=self.timestamp if self.shared is False else None,
            duration=self.duration if self.shared is False else None,
            endpoint=self.local_endpoint,
            annotations=full_annotations,
            binary_annotations=self.tags,
            remote_endpoint=self.remote_endpoint,
        )


def encode_pb_list(pb_spans):
    """Encode list of protobuf Spans to binary.

    :param pb_spans: list of protobuf Spans.
    :type pb_spans: list of zipkin_pb2.Span
    :return: encoded list.
    :rtype: bytes
    """
    pb_list = zipkin_pb2.ListOfSpans()
    pb_list.spans.extend(pb_spans)
    return pb_list.SerializeToString()

def encode_pb_list ( pb_spans ) : pb_list = zipkin_pb2 . ListOfSpans ( ) pb_list . spans . extend ( pb_spans ) return pb_list . SerializeToString ( )

Encode list of protobuf Spans to binary .


def create_protobuf_span(span):
    """Converts a py_zipkin Span in a protobuf Span.

    :param span: py_zipkin Span to convert.
    :type span: py_zipkin.encoding.Span
    :return: protobuf's Span
    :rtype: zipkin_pb2.Span
    """

    # Protobuf's composite types (i.e. Span's local_endpoint) are immutable.
    # So we can't create a zipkin_pb2.Span here and then set the appropriate
    # fields since `pb_span.local_endpoint = zipkin_pb2.Endpoint` fails.
    # Instead we just create the kwargs and pass them in to the Span constructor.
    pb_kwargs = {}

    pb_kwargs['trace_id'] = _hex_to_bytes(span.trace_id)

    if span.parent_id:
        pb_kwargs['parent_id'] = _hex_to_bytes(span.parent_id)

    pb_kwargs['id'] = _hex_to_bytes(span.span_id)

    pb_kind = _get_protobuf_kind(span.kind)
    if pb_kind:
        pb_kwargs['kind'] = pb_kind

    if span.name:
        pb_kwargs['name'] = span.name
    if span.timestamp:
        pb_kwargs['timestamp'] = int(span.timestamp * 1000 * 1000)
    if span.duration:
        pb_kwargs['duration'] = int(span.duration * 1000 * 1000)

    if span.local_endpoint:
        pb_kwargs['local_endpoint'] = _convert_endpoint(span.local_endpoint)

    if span.remote_endpoint:
        pb_kwargs['remote_endpoint'] = _convert_endpoint(span.remote_endpoint)

    if len(span.annotations) > 0:
        pb_kwargs['annotations'] = _convert_annotations(span.annotations)

    if len(span.tags) > 0:
        pb_kwargs['tags'] = span.tags

    if span.debug:
        pb_kwargs['debug'] = span.debug

    if span.shared:
        pb_kwargs['shared'] = span.shared

    return zipkin_pb2.Span(**pb_kwargs)

Converts a py_zipkin Span in a protobuf Span .


def _hex_to_bytes(hex_id):
    """Encodes to hexadecimal ids to big-endian binary.

    :param hex_id: hexadecimal id to encode.
    :type hex_id: str
    :return: binary representation.
    :type: bytes
    """
    if len(hex_id) <= 16:
        int_id = unsigned_hex_to_signed_int(hex_id)
        return struct.pack('>q', int_id)
    else:
        # There's no 16-bytes encoding in Python's struct. So we convert the
        # id as 2 64 bit ids and then concatenate the result.

        # NOTE: we count 16 chars from the right (:-16) rather than the left so
        # that ids with less than 32 chars will be correctly pre-padded with 0s.
        high_id = unsigned_hex_to_signed_int(hex_id[:-16])
        high_bin = struct.pack('>q', high_id)

        low_id = unsigned_hex_to_signed_int(hex_id[-16:])
        low_bin = struct.pack('>q', low_id)

        return high_bin + low_bin

Encodes to hexadecimal ids to big - endian binary .


def _get_protobuf_kind(kind):
    """Converts py_zipkin's Kind to Protobuf's Kind.

    :param kind: py_zipkin's Kind.
    :type kind: py_zipkin.Kind
    :return: correcponding protobuf's kind value.
    :rtype: zipkin_pb2.Span.Kind
    """
    if kind == Kind.CLIENT:
        return zipkin_pb2.Span.CLIENT
    elif kind == Kind.SERVER:
        return zipkin_pb2.Span.SERVER
    elif kind == Kind.PRODUCER:
        return zipkin_pb2.Span.PRODUCER
    elif kind == Kind.CONSUMER:
        return zipkin_pb2.Span.CONSUMER
    return None

def _get_protobuf_kind ( kind ) : if kind == Kind . CLIENT : return zipkin_pb2 . Span . CLIENT elif kind == Kind . SERVER : return zipkin_pb2 . Span . SERVER elif kind == Kind . PRODUCER : return zipkin_pb2 . Span . PRODUCER elif kind == Kind . CONSUMER : return zipkin_pb2 . Span . CONSUMER return None

Converts py_zipkin s Kind to Protobuf s Kind .


def _convert_endpoint(endpoint):
    """Converts py_zipkin's Endpoint to Protobuf's Endpoint.

    :param endpoint: py_zipkins' endpoint to convert.
    :type endpoint: py_zipkin.encoding.Endpoint
    :return: corresponding protobuf's endpoint.
    :rtype: zipkin_pb2.Endpoint
    """
    pb_endpoint = zipkin_pb2.Endpoint()

    if endpoint.service_name:
        pb_endpoint.service_name = endpoint.service_name
    if endpoint.port and endpoint.port != 0:
        pb_endpoint.port = endpoint.port
    if endpoint.ipv4:
        pb_endpoint.ipv4 = socket.inet_pton(socket.AF_INET, endpoint.ipv4)
    if endpoint.ipv6:
        pb_endpoint.ipv6 = socket.inet_pton(socket.AF_INET6, endpoint.ipv6)

    return pb_endpoint

def _convert_endpoint ( endpoint ) : pb_endpoint = zipkin_pb2 . Endpoint ( ) if endpoint . service_name : pb_endpoint . service_name = endpoint . service_name if endpoint . port and endpoint . port != 0 : pb_endpoint . port = endpoint . port if endpoint . ipv4 : pb_endpoint . ipv4 = socket . inet_pton ( socket . AF_INET , endpoint . ipv4 ) if endpoint . ipv6 : pb_endpoint . ipv6 = socket . inet_pton ( socket . AF_INET6 , endpoint . ipv6 ) return pb_endpoint

Converts py_zipkin s Endpoint to Protobuf s Endpoint .


def _convert_annotations(annotations):
    """Converts py_zipkin's annotations dict to protobuf.

    :param annotations: annotations dict.
    :type annotations: dict
    :return: corresponding protobuf's list of annotations.
    :rtype: list
    """
    pb_annotations = []
    for value, ts in annotations.items():
        pb_annotations.append(zipkin_pb2.Annotation(
            timestamp=int(ts * 1000 * 1000),
            value=value,
        ))
    return pb_annotations

def _convert_annotations ( annotations ) : pb_annotations = [ ] for value , ts in annotations . items ( ) : pb_annotations . append ( zipkin_pb2 . Annotation ( timestamp = int ( ts * 1000 * 1000 ) , value = value , ) ) return pb_annotations

Converts py_zipkin s annotations dict to protobuf .


def create_annotation(timestamp, value, host):
    """
    Create a zipkin annotation object

    :param timestamp: timestamp of when the annotation occured in microseconds
    :param value: name of the annotation, such as 'sr'
    :param host: zipkin endpoint object

    :returns: zipkin annotation object
    """
    return zipkin_core.Annotation(timestamp=timestamp, value=value, host=host)

def create_annotation ( timestamp , value , host ) : return zipkin_core . Annotation ( timestamp = timestamp , value = value , host = host )


def create_binary_annotation(key, value, annotation_type, host):
    """
    Create a zipkin binary annotation object

    :param key: name of the annotation, such as 'http.uri'
    :param value: value of the annotation, such as a URI
    :param annotation_type: type of annotation, such as AnnotationType.I32
    :param host: zipkin endpoint object

    :returns: zipkin binary annotation object
    """
    return zipkin_core.BinaryAnnotation(
        key=key,
        value=value,
        annotation_type=annotation_type,
        host=host,
    )

def create_binary_annotation ( key , value , annotation_type , host ) : return zipkin_core . BinaryAnnotation ( key = key , value = value , annotation_type = annotation_type , host = host , )


def create_endpoint(port=0, service_name='unknown', ipv4=None, ipv6=None):
    """Create a zipkin Endpoint object.

    An Endpoint object holds information about the network context of a span.

    :param port: int value of the port. Defaults to 0
    :param service_name: service name as a str. Defaults to 'unknown'
    :param ipv4: ipv4 host address
    :param ipv6: ipv6 host address
    :returns: thrift Endpoint object
    """
    ipv4_int = 0
    ipv6_binary = None

    # Convert ip address to network byte order
    if ipv4:
        ipv4_int = struct.unpack('!i', socket.inet_pton(socket.AF_INET, ipv4))[0]

    if ipv6:
        ipv6_binary = socket.inet_pton(socket.AF_INET6, ipv6)

    # Zipkin passes unsigned values in signed types because Thrift has no
    # unsigned types, so we have to convert the value.
    port = struct.unpack('h', struct.pack('H', port))[0]
    return zipkin_core.Endpoint(
        ipv4=ipv4_int,
        ipv6=ipv6_binary,
        port=port,
        service_name=service_name,
    )


def copy_endpoint_with_new_service_name(endpoint, service_name):
    """Copies a copy of a given endpoint with a new service name.
    This should be very fast, on the order of several microseconds.

    :param endpoint: existing zipkin_core.Endpoint object
    :param service_name: str of new service name
    :returns: zipkin Endpoint object
    """
    return zipkin_core.Endpoint(
        ipv4=endpoint.ipv4,
        port=endpoint.port,
        service_name=service_name,
    )

def copy_endpoint_with_new_service_name ( endpoint , service_name ) : return zipkin_core . Endpoint ( ipv4 = endpoint . ipv4 , port = endpoint . port , service_name = service_name , )

Copies a copy of a given endpoint with a new service name . This should be very fast on the order of several microseconds .


def annotation_list_builder(annotations, host):
    """
    Reformat annotations dict to return list of corresponding zipkin_core objects.

    :param annotations: dict containing key as annotation name,
                        value being timestamp in seconds(float).
    :type host: :class:`zipkin_core.Endpoint`
    :returns: a list of annotation zipkin_core objects
    :rtype: list
    """
    return [
        create_annotation(int(timestamp * 1000000), key, host)
        for key, timestamp in annotations.items()
    ]

def annotation_list_builder ( annotations , host ) : return [ create_annotation ( int ( timestamp * 1000000 ) , key , host ) for key , timestamp in annotations . items ( ) ]

Reformat annotations dict to return list of corresponding zipkin_core objects .


def binary_annotation_list_builder(binary_annotations, host):
    """
    Reformat binary annotations dict to return list of zipkin_core objects. The
    value of the binary annotations MUST be in string format.

    :param binary_annotations: dict with key, value being the name and value
                               of the binary annotation being logged.
    :type host: :class:`zipkin_core.Endpoint`
    :returns: a list of binary annotation zipkin_core objects
    :rtype: list
    """
    # TODO: Remove the type hard-coding of STRING to take it as a param option.
    ann_type = zipkin_core.AnnotationType.STRING
    return [
        create_binary_annotation(key, str(value), ann_type, host)
        for key, value in binary_annotations.items()
    ]

Reformat binary annotations dict to return list of zipkin_core objects . The value of the binary annotations MUST be in string format .


def create_span(
    span_id,
    parent_span_id,
    trace_id,
    span_name,
    annotations,
    binary_annotations,
    timestamp_s,
    duration_s,
):
    """Takes a bunch of span attributes and returns a thriftpy2 representation
    of the span. Timestamps passed in are in seconds, they're converted to
    microseconds before thrift encoding.
    """
    # Check if trace_id is 128-bit. If so, record trace_id_high separately.
    trace_id_length = len(trace_id)
    trace_id_high = None
    if trace_id_length > 16:
        assert trace_id_length == 32
        trace_id, trace_id_high = trace_id[16:], trace_id[:16]

    if trace_id_high:
        trace_id_high = unsigned_hex_to_signed_int(trace_id_high)

    span_dict = {
        'trace_id': unsigned_hex_to_signed_int(trace_id),
        'name': span_name,
        'id': unsigned_hex_to_signed_int(span_id),
        'annotations': annotations,
        'binary_annotations': binary_annotations,
        'timestamp': int(timestamp_s * 1000000) if timestamp_s else None,
        'duration': int(duration_s * 1000000) if duration_s else None,
        'trace_id_high': trace_id_high,
    }
    if parent_span_id:
        span_dict['parent_id'] = unsigned_hex_to_signed_int(parent_span_id)
    return zipkin_core.Span(**span_dict)

Takes a bunch of span attributes and returns a thriftpy2 representation of the span . Timestamps passed in are in seconds they re converted to microseconds before thrift encoding .


def span_to_bytes(thrift_span):
    """
    Returns a TBinaryProtocol encoded Thrift span.

    :param thrift_span: thrift object to encode.
    :returns: thrift object in TBinaryProtocol format bytes.
    """
    transport = TMemoryBuffer()
    protocol = TBinaryProtocol(transport)
    thrift_span.write(protocol)

    return bytes(transport.getvalue())

def span_to_bytes ( thrift_span ) : transport = TMemoryBuffer ( ) protocol = TBinaryProtocol ( transport ) thrift_span . write ( protocol ) return bytes ( transport . getvalue ( ) )

Returns a TBinaryProtocol encoded Thrift span .


def encode_bytes_list(binary_thrift_obj_list):  # pragma: no cover
    """
    Returns a TBinaryProtocol encoded list of Thrift objects.

    :param binary_thrift_obj_list: list of TBinaryProtocol objects to encode.
    :returns: bynary object representing the encoded list.
    """
    transport = TMemoryBuffer()
    write_list_begin(transport, TType.STRUCT, len(binary_thrift_obj_list))
    for thrift_bin in binary_thrift_obj_list:
        transport.write(thrift_bin)

    return bytes(transport.getvalue())

def
encode_bytes_list
(
binary_thrift_obj_list
)
:
# pragma: no cover
transport
=
TMemoryBuffer
(
)
write_list_begin
(
transport
,
TType
.
STRUCT
,
len
(
binary_thrift_obj_list
)
)
for
thrift_bin
in
binary_thrift_obj_list
:
transport
.
write
(
thrift_bin
)
return
bytes
(
transport
.
getvalue
(
)
)

Returns a TBinaryProtocol encoded list of Thrift objects .


def detect_span_version_and_encoding(message):
    """Returns the span type and encoding for the message provided.

    The logic in this function is a Python port of
    https://github.com/openzipkin/zipkin/blob/master/zipkin/src/main/java/zipkin/internal/DetectingSpanDecoder.java

    :param message: span to perform operations on.
    :type message: byte array
    :returns: span encoding.
    :rtype: Encoding
    """
    # In case message is sent in as non-bytearray format,
    # safeguard convert to bytearray before handling
    if isinstance(message, six.string_types):
        # Even six.b is not enough to handle the py2/3 difference since
        # it uses latin-1 as default encoding and not utf-8.
        if six.PY2:
            message = six.b(message)  # pragma: no cover
        else:
            message = message.encode('utf-8')  # pragma: no cover

    if len(message) < 2:
        raise ZipkinError("Invalid span format. Message too short.")

    # Check for binary format
    if six.byte2int(message) <= 16:
        if six.byte2int(message) == 10 and six.byte2int(message[1:2]) != 0:
            return Encoding.V2_PROTO3
        return Encoding.V1_THRIFT

    str_msg = message.decode('utf-8')

    # JSON case for list of spans
    if str_msg[0] == '[':
        span_list = json.loads(str_msg)
        if len(span_list) > 0:
            # Assumption: All spans in a list are the same version
            # Logic: Search for identifying fields in all spans, if any span can
            # be strictly identified to a version, return that version.
            # Otherwise, if no spans could be strictly identified, default to V2.
            for span in span_list:
                if any(word in span for word in _V2_ATTRIBUTES):
                    return Encoding.V2_JSON
                elif (
                    'binaryAnnotations' in span or
                    (
                        'annotations' in span and
                        'endpoint' in span['annotations']
                    )
                ):
                    return Encoding.V1_JSON
            return Encoding.V2_JSON

    raise ZipkinError("Unknown or unsupported span encoding")

Returns the span type and encoding for the message provided .


def convert_spans(spans, output_encoding, input_encoding=None):
    """Converts encoded spans to a different encoding.

    param spans: encoded input spans.
    type spans: byte array
    param output_encoding: desired output encoding.
    type output_encoding: Encoding
    param input_encoding: optional input encoding. If this is not specified, it'll
        try to understand the encoding automatically by inspecting the input spans.
    type input_encoding: Encoding
    :returns: encoded spans.
    :rtype: byte array
    """
    if not isinstance(input_encoding, Encoding):
        input_encoding = detect_span_version_and_encoding(message=spans)

    if input_encoding == output_encoding:
        return spans

    decoder = get_decoder(input_encoding)
    encoder = get_encoder(output_encoding)
    decoded_spans = decoder.decode_spans(spans)
    output_spans = []

    # Encode each indivicual span
    for span in decoded_spans:
        output_spans.append(encoder.encode_span(span))

    # Outputs from encoder.encode_span() can be easily concatenated in a list
    return encoder.encode_queue(output_spans)

Converts encoded spans to a different encoding .


def push_zipkin_attrs(zipkin_attr):
    """Stores the zipkin attributes to thread local.

    .. deprecated::
       Use the Tracer interface which offers better multi-threading support.
       push_zipkin_attrs will be removed in version 1.0.

    :param zipkin_attr: tuple containing zipkin related attrs
    :type zipkin_attr: :class:`zipkin.ZipkinAttrs`
    """
    from py_zipkin.storage import ThreadLocalStack
    log.warning('push_zipkin_attrs is deprecated. See DEPRECATIONS.rst for'
                'details on how to migrate to using Tracer.')
    return ThreadLocalStack().push(zipkin_attr)

Stores the zipkin attributes to thread local .


def encode_span(self, v2_span):
        """Encodes the current span to thrift."""
        span = v2_span.build_v1_span()

        thrift_endpoint = thrift.create_endpoint(
            span.endpoint.port,
            span.endpoint.service_name,
            span.endpoint.ipv4,
            span.endpoint.ipv6,
        )

        thrift_annotations = thrift.annotation_list_builder(
            span.annotations,
            thrift_endpoint,
        )

        thrift_binary_annotations = thrift.binary_annotation_list_builder(
            span.binary_annotations,
            thrift_endpoint,
        )

        # Add sa/ca binary annotations
        if v2_span.remote_endpoint:
            self.encode_remote_endpoint(
                v2_span.remote_endpoint,
                v2_span.kind,
                thrift_binary_annotations,
            )

        thrift_span = thrift.create_span(
            span.id,
            span.parent_id,
            span.trace_id,
            span.name,
            thrift_annotations,
            thrift_binary_annotations,
            span.timestamp,
            span.duration,
        )

        encoded_span = thrift.span_to_bytes(thrift_span)
        return encoded_span

def
encode_span
(
self
,
v2_span
)
:
span
=
v2_span
.
build_v1_span
(
)
thrift_endpoint
=
thrift
.
create_endpoint
(
span
.
endpoint
.
port
,
span
.
endpoint
.
service_name
,
span
.
endpoint
.
ipv4
,
span
.
endpoint
.
ipv6
,
)
thrift_annotations
=
thrift
.
annotation_list_builder
(
span
.
annotations
,
thrift_endpoint
,
)
thrift_binary_annotations
=
thrift
.
binary_annotation_list_builder
(
span
.
binary_annotations
,
thrift_endpoint
,
)
# Add sa/ca binary annotations
if
v2_span
.
remote_endpoint
:
self
.
encode_remote_endpoint
(
v2_span
.
remote_endpoint
,
v2_span
.
kind
,
thrift_binary_annotations
,
)
thrift_span
=
thrift
.
create_span
(
span
.
id
,
span
.
parent_id
,
span
.
trace_id
,
span
.
name
,
thrift_annotations
,
thrift_binary_annotations
,
span
.
timestamp
,
span
.
duration
,
)
encoded_span
=
thrift
.
span_to_bytes
(
thrift_span
)
return
encoded_span


def _create_json_endpoint(self, endpoint, is_v1):
        """Converts an Endpoint to a JSON endpoint dict.

        :param endpoint: endpoint object to convert.
        :type endpoint: Endpoint
        :param is_v1: whether we're serializing a v1 span. This is needed since
            in v1 some fields default to an empty string rather than being
            dropped if they're not set.
        :type is_v1: bool
        :return: dict representing a JSON endpoint.
        :rtype: dict
        """
        json_endpoint = {}

        if endpoint.service_name:
            json_endpoint['serviceName'] = endpoint.service_name
        elif is_v1:
            # serviceName is mandatory in v1
            json_endpoint['serviceName'] = ""
        if endpoint.port and endpoint.port != 0:
            json_endpoint['port'] = endpoint.port
        if endpoint.ipv4 is not None:
            json_endpoint['ipv4'] = endpoint.ipv4
        if endpoint.ipv6 is not None:
            json_endpoint['ipv6'] = endpoint.ipv6

        return json_endpoint

def
_create_json_endpoint
(
self
,
endpoint
,
is_v1
)
:
json_endpoint
=
{
}
if
endpoint
.
service_name
:
json_endpoint
[
'serviceName'
]
=
endpoint
.
service_name
elif
is_v1
:
# serviceName is mandatory in v1
json_endpoint
[
'serviceName'
]
=
""
if
endpoint
.
port
and
endpoint
.
port
!=
0
:
json_endpoint
[
'port'
]
=
endpoint
.
port
if
endpoint
.
ipv4
is
not
:
json_endpoint
[
'ipv4'
]
=
endpoint
.
ipv4
if
endpoint
.
ipv6
is
not
:
json_endpoint
[
'ipv6'
]
=
endpoint
.
ipv6
return
json_endpoint

Converts an Endpoint to a JSON endpoint dict .


def encode_span(self, span):
        """Encodes a single span to protobuf."""
        if not protobuf.installed():
            raise ZipkinError(
                'protobuf encoding requires installing the protobuf\'s extra '
                'requirements. Use py-zipkin[protobuf] in your requirements.txt.'
            )

        pb_span = protobuf.create_protobuf_span(span)
        return protobuf.encode_pb_list([pb_span])


def decode_spans(self, spans):
        """Decodes an encoded list of spans.

        :param spans: encoded list of spans
        :type spans: bytes
        :return: list of spans
        :rtype: list of Span
        """
        decoded_spans = []
        transport = TMemoryBuffer(spans)

        if six.byte2int(spans) == TType.STRUCT:
            _, size = read_list_begin(transport)
        else:
            size = 1

        for _ in range(size):
            span = zipkin_core.Span()
            span.read(TBinaryProtocol(transport))
            decoded_spans.append(self._decode_thrift_span(span))
        return decoded_spans

def decode_spans ( self , spans ) : decoded_spans = [ ] transport = TMemoryBuffer ( spans ) if six . byte2int ( spans ) == TType . STRUCT : _ , size = read_list_begin ( transport ) else : size = 1 for _ in range ( size ) : span = zipkin_core . Span ( ) span . read ( TBinaryProtocol ( transport ) ) decoded_spans . append ( self . _decode_thrift_span ( span ) ) return decoded_spans


def _convert_from_thrift_endpoint(self, thrift_endpoint):
        """Accepts a thrift decoded endpoint and converts it to an Endpoint.

        :param thrift_endpoint: thrift encoded endpoint
        :type thrift_endpoint: thrift endpoint
        :returns: decoded endpoint
        :rtype: Encoding
        """
        ipv4 = None
        ipv6 = None
        port = struct.unpack('H', struct.pack('h', thrift_endpoint.port))[0]

        if thrift_endpoint.ipv4 != 0:
            ipv4 = socket.inet_ntop(
                socket.AF_INET,
                struct.pack('!i', thrift_endpoint.ipv4),
            )

        if thrift_endpoint.ipv6:
            ipv6 = socket.inet_ntop(socket.AF_INET6, thrift_endpoint.ipv6)

        return Endpoint(
            service_name=thrift_endpoint.service_name,
            ipv4=ipv4,
            ipv6=ipv6,
            port=port,
        )

def _convert_from_thrift_endpoint ( self , thrift_endpoint ) : ipv4 = None ipv6 = None port = struct . unpack ( 'H' , struct . pack ( 'h' , thrift_endpoint . port ) ) [ 0 ] if thrift_endpoint . ipv4 != 0 : ipv4 = socket . inet_ntop ( socket . AF_INET , struct . pack ( '!i' , thrift_endpoint . ipv4 ) , ) if thrift_endpoint . ipv6 : ipv6 = socket . inet_ntop ( socket . AF_INET6 , thrift_endpoint . ipv6 ) return Endpoint ( service_name = thrift_endpoint . service_name , ipv4 = ipv4 , ipv6 = ipv6 , port = port , )

Accepts a thrift decoded endpoint and converts it to an Endpoint .


def _decode_thrift_annotations(self, thrift_annotations):
        """Accepts a thrift annotation and converts it to a v1 annotation.

        :param thrift_annotations: list of thrift annotations.
        :type thrift_annotations: list of zipkin_core.Span.Annotation
        :returns: (annotations, local_endpoint, kind)
        """
        local_endpoint = None
        kind = Kind.LOCAL
        all_annotations = {}
        timestamp = None
        duration = None

        for thrift_annotation in thrift_annotations:
            all_annotations[thrift_annotation.value] = thrift_annotation.timestamp
            if thrift_annotation.host:
                local_endpoint = self._convert_from_thrift_endpoint(
                    thrift_annotation.host,
                )

        if 'cs' in all_annotations and 'sr' not in all_annotations:
            kind = Kind.CLIENT
            timestamp = all_annotations['cs']
            duration = all_annotations['cr'] - all_annotations['cs']
        elif 'cs' not in all_annotations and 'sr' in all_annotations:
            kind = Kind.SERVER
            timestamp = all_annotations['sr']
            duration = all_annotations['ss'] - all_annotations['sr']

        annotations = {
            name: self.seconds(ts) for name, ts in all_annotations.items()
            if name not in _DROP_ANNOTATIONS
        }

        return annotations, local_endpoint, kind, timestamp, duration

def _decode_thrift_annotations ( self , thrift_annotations ) : local_endpoint = None kind = Kind . LOCAL all_annotations = { } timestamp = None duration = None for thrift_annotation in thrift_annotations : all_annotations [ thrift_annotation . value ] = thrift_annotation . timestamp if thrift_annotation . host : local_endpoint = self . _convert_from_thrift_endpoint ( thrift_annotation . host , ) if 'cs' in all_annotations and 'sr' not in all_annotations : kind = Kind . CLIENT timestamp = all_annotations [ 'cs' ] duration = all_annotations [ 'cr' ] - all_annotations [ 'cs' ] elif 'cs' not in all_annotations and 'sr' in all_annotations : kind = Kind . SERVER timestamp = all_annotations [ 'sr' ] duration = all_annotations [ 'ss' ] - all_annotations [ 'sr' ] annotations = { name : self . seconds ( ts ) for name , ts in all_annotations . items ( ) if name not in _DROP_ANNOTATIONS } return annotations , local_endpoint , kind , timestamp , duration

Accepts a thrift annotation and converts it to a v1 annotation .


def _convert_from_thrift_binary_annotations(self, thrift_binary_annotations):
        """Accepts a thrift decoded binary annotation and converts it
        to a v1 binary annotation.
        """
        tags = {}
        local_endpoint = None
        remote_endpoint = None

        for binary_annotation in thrift_binary_annotations:
            if binary_annotation.key == 'sa':
                remote_endpoint = self._convert_from_thrift_endpoint(
                    thrift_endpoint=binary_annotation.host,
                )
            else:
                key = binary_annotation.key

                annotation_type = binary_annotation.annotation_type
                value = binary_annotation.value

                if annotation_type == zipkin_core.AnnotationType.BOOL:
                    tags[key] = "true" if value == 1 else "false"
                elif annotation_type == zipkin_core.AnnotationType.STRING:
                    tags[key] = str(value)
                else:
                    log.warning('Only STRING and BOOL binary annotations are '
                                'supported right now and can be properly decoded.')

                if binary_annotation.host:
                    local_endpoint = self._convert_from_thrift_endpoint(
                        thrift_endpoint=binary_annotation.host,
                    )

        return tags, local_endpoint, remote_endpoint

Accepts a thrift decoded binary annotation and converts it to a v1 binary annotation .


def _decode_thrift_span(self, thrift_span):
        """Decodes a thrift span.

        :param thrift_span: thrift span
        :type thrift_span: thrift Span object
        :returns: span builder representing this span
        :rtype: Span
        """
        parent_id = None
        local_endpoint = None
        annotations = {}
        tags = {}
        kind = Kind.LOCAL
        remote_endpoint = None
        timestamp = None
        duration = None

        if thrift_span.parent_id:
            parent_id = self._convert_unsigned_long_to_lower_hex(
                thrift_span.parent_id,
            )

        if thrift_span.annotations:
            annotations, local_endpoint, kind, timestamp, duration = \
                self._decode_thrift_annotations(thrift_span.annotations)

        if thrift_span.binary_annotations:
            tags, local_endpoint, remote_endpoint = \
                self._convert_from_thrift_binary_annotations(
                    thrift_span.binary_annotations,
                )

        trace_id = self._convert_trace_id_to_string(
            thrift_span.trace_id,
            thrift_span.trace_id_high,
        )

        return Span(
            trace_id=trace_id,
            name=thrift_span.name,
            parent_id=parent_id,
            span_id=self._convert_unsigned_long_to_lower_hex(thrift_span.id),
            kind=kind,
            timestamp=self.seconds(timestamp or thrift_span.timestamp),
            duration=self.seconds(duration or thrift_span.duration),
            local_endpoint=local_endpoint,
            remote_endpoint=remote_endpoint,
            shared=(kind == Kind.SERVER and thrift_span.timestamp is None),
            annotations=annotations,
            tags=tags,
        )

def _decode_thrift_span ( self , thrift_span ) : parent_id = None local_endpoint = None annotations = { } tags = { } kind = Kind . LOCAL remote_endpoint = None timestamp = None duration = None if thrift_span . parent_id : parent_id = self . _convert_unsigned_long_to_lower_hex ( thrift_span . parent_id , ) if thrift_span . annotations : annotations , local_endpoint , kind , timestamp , duration = self . _decode_thrift_annotations ( thrift_span . annotations ) if thrift_span . binary_annotations : tags , local_endpoint , remote_endpoint = self . _convert_from_thrift_binary_annotations ( thrift_span . binary_annotations , ) trace_id = self . _convert_trace_id_to_string ( thrift_span . trace_id , thrift_span . trace_id_high , ) return Span ( trace_id = trace_id , name = thrift_span . name , parent_id = parent_id , span_id = self . _convert_unsigned_long_to_lower_hex ( thrift_span . id ) , kind = kind , timestamp = self . seconds ( timestamp or thrift_span . timestamp ) , duration = self . seconds ( duration or thrift_span . duration ) , local_endpoint = local_endpoint , remote_endpoint = remote_endpoint , shared = ( kind == Kind . SERVER and thrift_span . timestamp is None ) , annotations = annotations , tags = tags , )


def _convert_trace_id_to_string(self, trace_id, trace_id_high=None):
        """
        Converts the provided traceId hex value with optional high bits
        to a string.

        :param trace_id: the value of the trace ID
        :type trace_id: int
        :param trace_id_high: the high bits of the trace ID
        :type trace_id: int
        :returns: trace_id_high + trace_id as a string
        """
        if trace_id_high is not None:
            result = bytearray(32)
            self._write_hex_long(result, 0, trace_id_high)
            self._write_hex_long(result, 16, trace_id)
            return result.decode("utf8")

        result = bytearray(16)
        self._write_hex_long(result, 0, trace_id)
        return result.decode("utf8")

def _convert_trace_id_to_string ( self , trace_id , trace_id_high = None ) : if trace_id_high is not None : result = bytearray ( 32 ) self . _write_hex_long ( result , 0 , trace_id_high ) self . _write_hex_long ( result , 16 , trace_id ) return result . decode ( "utf8" ) result = bytearray ( 16 ) self . _write_hex_long ( result , 0 , trace_id ) return result . decode ( "utf8" )

Converts the provided traceId hex value with optional high bits to a string .


def _convert_unsigned_long_to_lower_hex(self, value):
        """
        Converts the provided unsigned long value to a hex string.

        :param value: the value to convert
        :type value: unsigned long
        :returns: value as a hex string
        """
        result = bytearray(16)
        self._write_hex_long(result, 0, value)
        return result.decode("utf8")

def _convert_unsigned_long_to_lower_hex ( self , value ) : result = bytearray ( 16 ) self . _write_hex_long ( result , 0 , value ) return result . decode ( "utf8" )

Converts the provided unsigned long value to a hex string .


def _write_hex_long(self, data, pos, value):
        """
        Writes an unsigned long value across a byte array.

        :param data: the buffer to write the value to
        :type data: bytearray
        :param pos: the starting position
        :type pos: int
        :param value: the value to write
        :type value: unsigned long
        """
        self._write_hex_byte(data, pos + 0, (value >> 56) & 0xff)
        self._write_hex_byte(data, pos + 2, (value >> 48) & 0xff)
        self._write_hex_byte(data, pos + 4, (value >> 40) & 0xff)
        self._write_hex_byte(data, pos + 6, (value >> 32) & 0xff)
        self._write_hex_byte(data, pos + 8, (value >> 24) & 0xff)
        self._write_hex_byte(data, pos + 10, (value >> 16) & 0xff)
        self._write_hex_byte(data, pos + 12, (value >> 8) & 0xff)
        self._write_hex_byte(data, pos + 14, (value & 0xff))

def _write_hex_long ( self , data , pos , value ) : self . _write_hex_byte ( data , pos + 0 , ( value >> 56 ) & 0xff ) self . _write_hex_byte ( data , pos + 2 , ( value >> 48 ) & 0xff ) self . _write_hex_byte ( data , pos + 4 , ( value >> 40 ) & 0xff ) self . _write_hex_byte ( data , pos + 6 , ( value >> 32 ) & 0xff ) self . _write_hex_byte ( data , pos + 8 , ( value >> 24 ) & 0xff ) self . _write_hex_byte ( data , pos + 10 , ( value >> 16 ) & 0xff ) self . _write_hex_byte ( data , pos + 12 , ( value >> 8 ) & 0xff ) self . _write_hex_byte ( data , pos + 14 , ( value & 0xff ) )

Writes an unsigned long value across a byte array .


def date_fixup_pre_processor(transactions, tag, tag_dict, *args):
    """
    Replace illegal February 29, 30 dates with the last day of February.

    German banks use a variant of the 30/360 interest rate calculation,
    where each month has always 30 days even February. Python's datetime
    module won't accept such dates.
    """
    if tag_dict['month'] == '02':
        year = int(tag_dict['year'], 10)
        _, max_month_day = calendar.monthrange(year, 2)
        if int(tag_dict['day'], 10) > max_month_day:
            tag_dict['day'] = str(max_month_day)

    return tag_dict

def date_fixup_pre_processor ( transactions , tag , tag_dict , * args ) : if tag_dict [ 'month' ] == '02' : year = int ( tag_dict [ 'year' ] , 10 ) _ , max_month_day = calendar . monthrange ( year , 2 ) if int ( tag_dict [ 'day' ] , 10 ) > max_month_day : tag_dict [ 'day' ] = str ( max_month_day ) return tag_dict

Replace illegal February 29 30 dates with the last day of February .


def mBank_set_transaction_code(transactions, tag, tag_dict, *args):
    """
    mBank Collect uses transaction code 911 to distinguish icoming mass
    payments transactions, adding transaction_code may be helpful in further
    processing
    """
    tag_dict['transaction_code'] = int(
        tag_dict[tag.slug].split(';')[0].split(' ', 1)[0])

    return tag_dict

def
mBank_set_transaction_code
(
transactions
,
tag
,
tag_dict
,
*
args
)
:
tag_dict
[
'transaction_code'
]
=
int
(
tag_dict
[
tag
.
slug
]
.
split
(
';'
)
[
0
]
.
split
(
' '
,
1
)
[
0
]
)
return
tag_dict

mBank Collect uses transaction code 911 to distinguish icoming mass payments transactions adding transaction_code may be helpful in further processing


def mBank_set_iph_id(transactions, tag, tag_dict, *args):
    """
    mBank Collect uses ID IPH to distinguish between virtual accounts,
    adding iph_id may be helpful in further processing
    """
    matches = iph_id_re.search(tag_dict[tag.slug])

    if matches:  # pragma no branch
        tag_dict['iph_id'] = matches.groupdict()['iph_id']

    return tag_dict

def
mBank_set_iph_id
(
transactions
,
tag
,
tag_dict
,
*
args
)
:
matches
=
iph_id_re
.
search
(
tag_dict
[
tag
.
slug
]
)
if
matches
:
# pragma no branch
tag_dict
[
'iph_id'
]
=
matches
.
groupdict
(
)
[
'iph_id'
]
return
tag_dict

mBank Collect uses ID IPH to distinguish between virtual accounts adding iph_id may be helpful in further processing


def mBank_set_tnr(transactions, tag, tag_dict, *args):
    """
    mBank Collect states TNR in transaction details as unique id for
    transactions, that may be used to identify the same transactions in
    different statement files eg. partial mt942 and full mt940
    Information about tnr uniqueness has been obtained from mBank support,
    it lacks in mt940 mBank specification.
    """

    matches = tnr_re.search(tag_dict[tag.slug])

    if matches:  # pragma no branch
        tag_dict['tnr'] = matches.groupdict()['tnr']

    return tag_dict

def
mBank_set_tnr
(
transactions
,
tag
,
tag_dict
,
*
args
)
:
matches
=
tnr_re
.
search
(
tag_dict
[
tag
.
slug
]
)
if
matches
:
# pragma no branch
tag_dict
[
'tnr'
]
=
matches
.
groupdict
(
)
[
'tnr'
]
return
tag_dict

mBank Collect states TNR in transaction details as unique id for transactions that may be used to identify the same transactions in different statement files eg . partial mt942 and full mt940 Information about tnr uniqueness has been obtained from mBank support it lacks in mt940 mBank specification .


def parse(self, data):
        '''Parses mt940 data, expects a string with data

        Args:
            data (str): The MT940 data

        Returns: :py:class:`list` of :py:class:`Transaction`
        '''
        # Remove extraneous whitespace and such
        data = '\n'.join(self.strip(data.split('\n')))

        # The pattern is a bit annoying to match by regex, even with a greedy
        # match it's difficult to get both the beginning and the end so we're
        # working around it in a safer way to get everything.
        tag_re = re.compile(
            r'^:\n?(?P<full_tag>(?P<tag>[0-9]{2}|NS)(?P<sub_tag>[A-Z])?):',
            re.MULTILINE)
        matches = list(tag_re.finditer(data))

        # identify valid matches
        valid_matches = list(self.sanatize_tag_id_matches(matches))

        for i, match in enumerate(valid_matches):
            tag_id = self.normalize_tag_id(match.group('tag'))

            # get tag instance corresponding to tag id
            tag = self.tags.get(match.group('full_tag')) \
                or self.tags[tag_id]

            # Nice trick to get all the text that is part of this tag, python
            # regex matches have a `end()` and `start()` to indicate the start
            # and end index of the match.

            if valid_matches[i + 1:]:
                tag_data = \
                    data[match.end():valid_matches[i + 1].start()].strip()
            else:
                tag_data = data[match.end():].strip()

            tag_dict = tag.parse(self, tag_data)

            # Preprocess data before creating the object

            for processor in self.processors.get('pre_%s' % tag.slug, []):
                tag_dict = processor(self, tag, tag_dict)

            result = tag(self, tag_dict)

            # Postprocess the object

            for processor in self.processors.get('post_%s' % tag.slug, []):
                result = processor(self, tag, tag_dict, result)

            # Creating a new transaction for :20: and :61: tags allows the
            # tags from :20: to :61: to be captured as part of the transaction.

            if isinstance(tag, mt940.tags.Statement):
                # Transactions only get a Transaction Reference Code ID from a
                # :61: tag which is why a new transaction is created if the
                # 'id' has a value.

                if not self.transactions:
                    transaction = Transaction(self)
                    self.transactions.append(transaction)

                if transaction.data.get('id'):
                    transaction = Transaction(self, result)
                    self.transactions.append(transaction)
                else:
                    transaction.data.update(result)
            elif issubclass(tag.scope, Transaction) and self.transactions:
                # Combine multiple results together as one string, Rabobank has
                # multiple :86: tags for a single transaction

                for k, v in _compat.iteritems(result):
                    if k in transaction.data and hasattr(v, 'strip'):
                        transaction.data[k] += '\n%s' % v.strip()
                    else:
                        transaction.data[k] = v

            elif issubclass(tag.scope, Transactions):  # pragma: no branch
                self.data.update(result)

        return self.transactions

Parses mt940 data expects a string with data


def parse(src, encoding=None):
    '''
    Parses mt940 data and returns transactions object

    :param src: file handler to read, filename to read or raw data as string
    :return: Collection of transactions
    :rtype: Transactions
    '''

    def safe_is_file(filename):
        try:
            return os.path.isfile(src)
        except ValueError:  # pragma: no cover
            return False

    if hasattr(src, 'read'):  # pragma: no branch
        data = src.read()
    elif safe_is_file(src):
        with open(src, 'rb') as fh:
            data = fh.read()
    else:  # pragma: no cover
        data = src

    if hasattr(data, 'decode'):  # pragma: no branch
        exception = None
        encodings = [encoding, 'utf-8', 'cp852', 'iso8859-15', 'latin1']

        for encoding in encodings:  # pragma: no cover
            if not encoding:
                continue

            try:
                data = data.decode(encoding)
                break
            except UnicodeDecodeError as e:
                exception = e
            except UnicodeEncodeError:
                break
        else:
            raise exception  # pragma: no cover

    transactions = mt940.models.Transactions()
    transactions.parse(data)

    return transactions

def
parse
(
src
,
encoding
=
)
:
def
safe_is_file
(
filename
)
:
try
:
return
os
.
path
.
isfile
(
src
)
except
ValueError
:
# pragma: no cover
return
False
if
hasattr
(
src
,
'read'
)
:
# pragma: no branch
data
=
src
.
read
(
)
elif
safe_is_file
(
src
)
:
with
open
(
src
,
'rb'
)
as
fh
:
data
=
fh
.
read
(
)
else
:
# pragma: no cover
data
=
src
if
hasattr
(
data
,
'decode'
)
:
# pragma: no branch
exception
=
encodings
=
[
encoding
,
'utf-8'
,
'cp852'
,
'iso8859-15'
,
'latin1'
]
for
encoding
in
encodings
:
# pragma: no cover
if
not
encoding
:
continue
try
:
data
=
data
.
decode
(
encoding
)
break
except
UnicodeDecodeError
as
e
:
exception
=
e
except
UnicodeEncodeError
:
break
else
:
raise
exception
# pragma: no cover
transactions
=
mt940
.
models
.
Transactions
(
)
transactions
.
parse
(
data
)
return
transactions


def join_lines(string, strip=Strip.BOTH):
    '''
    Join strings together and strip whitespace in between if needed
    '''
    lines = []

    for line in string.splitlines():
        if strip & Strip.RIGHT:
            line = line.rstrip()

        if strip & Strip.LEFT:
            line = line.lstrip()

        lines.append(line)

    return ''.join(lines)

def join_lines ( string , strip = Strip . BOTH ) : lines = [ ] for line in string . splitlines ( ) : if strip & Strip . RIGHT : line = line . rstrip ( ) if strip & Strip . LEFT : line = line . lstrip ( ) lines . append ( line ) return '' . join ( lines )


async def json_or_text(response):
    """Turns response into a properly formatted json or text object"""
    text = await response.text()
    if response.headers['Content-Type'] == 'application/json; charset=utf-8':
        return json.loads(text)
    return text

async
def
json_or_text
(
response
)
:
text
=
await
response
.
text
(
)
if
response
.
headers
[
'Content-Type'
]
==
'application/json; charset=utf-8'
:
return
json
.
loads
(
text
)
return
text


async def limited(until):
    """Handles the message shown when we are ratelimited"""
    duration = int(round(until - time.time()))
    mins = duration / 60
    fmt = 'We have exhausted a ratelimit quota. Retrying in %.2f seconds (%.3f minutes).'
    log.warn(fmt, duration, mins)


async def request(self, method, url, **kwargs):
        """Handles requests to the API"""
        rate_limiter = RateLimiter(max_calls=59, period=60, callback=limited)
        # handles ratelimits. max_calls is set to 59 because current implementation will retry in 60s after 60 calls is reached. DBL has a 1h block so obviously this doesn't work well, as it will get a 429 when 60 is reached.

        async with rate_limiter:  # this works but doesn't 'save' over restart. need a better implementation.

            if not self.token:
                raise UnauthorizedDetected('UnauthorizedDetected (status code: 401): No TOKEN provided')

            headers = {
                'User-Agent': self.user_agent,
                'Content-Type': 'application/json'
            }

            if 'json' in kwargs:
                kwargs['data'] = to_json(kwargs.pop('json'))

            kwargs['headers'] = headers
            headers['Authorization'] = self.token

            for tries in range(5):
                async with self.session.request(method, url, **kwargs) as resp:
                    log.debug('%s %s with %s has returned %s', method,
                              url, kwargs.get('data'), resp.status)

                    data = await json_or_text(resp)

                    if 300 > resp.status >= 200:
                        return data

                    if resp.status == 429:  # we are being ratelimited
                        fmt = 'We are being rate limited. Retrying in %.2f seconds (%.3f minutes).'

                        # sleep a bit
                        retry_after = json.loads(resp.headers.get('Retry-After'))
                        mins = retry_after / 60
                        log.warning(fmt, retry_after, mins)

                        # check if it's a global rate limit (True as only 1 ratelimit atm - /api/bots)
                        is_global = True  # is_global = data.get('global', False)
                        if is_global:
                            self._global_over.clear()

                        await asyncio.sleep(retry_after, loop=self.loop)
                        log.debug('Done sleeping for the rate limit. Retrying...')

                        # release the global lock now that the
                        # global rate limit has passed
                        if is_global:
                            self._global_over.set()
                            log.debug('Global rate limit is now over.')

                        continue

                    if resp.status == 400:
                        raise HTTPException(resp, data)
                    elif resp.status == 401:
                        raise Unauthorized(resp, data)
                    elif resp.status == 403:
                        raise Forbidden(resp, data)
                    elif resp.status == 404:
                        raise NotFound(resp, data)
                    else:
                        raise HTTPException(resp, data)
            # We've run out of retries, raise.
            raise HTTPException(resp, data)


async def get_bot_info(self, bot_id):
        '''Gets the information of the given Bot ID'''
        resp = await self.request('GET', '{}/bots/{}'.format(self.BASE, bot_id))
        resp['date'] = datetime.strptime(resp['date'], '%Y-%m-%dT%H:%M:%S.%fZ')
        for k in resp:
            if resp[k] == '':
                resp[k] = None
        return resp

async def get_bot_info ( self , bot_id ) : resp = await self . request ( 'GET' , '{}/bots/{}' . format ( self . BASE , bot_id ) ) resp [ 'date' ] = datetime . strptime ( resp [ 'date' ] , '%Y-%m-%dT%H:%M:%S.%fZ' ) for k in resp : if resp [ k ] == '' : resp [ k ] = None return resp


async def get_bots(self, limit, offset):
        '''Gets an object of bots on DBL'''
        if limit > 500:
            limit = 50
        return await self.request('GET', '{}/bots?limit={}&offset={}'.format(self.BASE, limit, offset))

async def get_bots ( self , limit , offset ) : if limit > 500 : limit = 50 return await self . request ( 'GET' , '{}/bots?limit={}&offset={}' . format ( self . BASE , limit , offset ) )


def read(self):
        """Read incoming message."""
        packet = self.packet
        with self.__read_lock:
            buffer = self.__buffer
            while len(buffer) < packet:
                buffer += self._read_data()
            length = self.__unpack(buffer[:packet])[0] + packet
            while len(buffer) < length:
                buffer += self._read_data()
            term, self.__buffer = decode(buffer[packet:])
        return term

def read ( self ) : packet = self . packet with self . __read_lock : buffer = self . __buffer while len ( buffer ) < packet : buffer += self . _read_data ( ) length = self . __unpack ( buffer [ : packet ] ) [ 0 ] + packet while len ( buffer ) < length : buffer += self . _read_data ( ) term , self . __buffer = decode ( buffer [ packet : ] ) return term


def write(self, message):
        """Write outgoing message."""
        data = encode(message, compressed=self.compressed)
        length = len(data)
        data = self.__pack(length) + data
        with self.__write_lock:
            while data:
                try:
                    n = os.write(self.out_d, data)
                except OSError as why:
                    if why.errno in (errno.EPIPE, errno.EINVAL):
                        raise EOFError()
                    raise
                if not n:
                    raise EOFError()
                data = data[n:]
        return length + self.packet

def write ( self , message ) : data = encode ( message , compressed = self . compressed ) length = len ( data ) data = self . __pack ( length ) + data with self . __write_lock : while data : try : n = os . write ( self . out_d , data ) except OSError as why : if why . errno in ( errno . EPIPE , errno . EINVAL ) : raise EOFError ( ) raise if not n : raise EOFError ( ) data = data [ n : ] return length + self . packet


def close(self):
        """Close port."""
        os.close(self.in_d)
        os.close(self.out_d)

def close ( self ) : os . close ( self . in_d ) os . close ( self . out_d )


def decode(string):
    """Decode Erlang external term."""
    if not string:
        raise IncompleteData(string)
    if string[0] != 131:
        raise ValueError("unknown protocol version: %r" % string[0])
    if string[1:2] == b'P':
        # compressed term
        if len(string) < 16:
            raise IncompleteData(string)
        d = decompressobj()
        term_string = d.decompress(string[6:]) + d.flush()
        uncompressed_size, = _int4_unpack(string[2:6])
        if len(term_string) != uncompressed_size:
            raise ValueError(
                "invalid compressed tag, "
                "%d bytes but got %d" % (uncompressed_size, len(term_string)))
        # tail data returned by decode_term() can be simple ignored
        term, _tail = decode_term(term_string)
        return term, d.unused_data
    return decode_term(string[1:])


def encode(term, compressed=False):
    """Encode Erlang external term."""
    encoded_term = encode_term(term)
    # False and 0 do not attempt compression.
    if compressed:
        if compressed is True:
            # default compression level of 6
            compressed = 6
        elif compressed < 0 or compressed > 9:
            raise ValueError("invalid compression level: %r" % (compressed,))
        zlib_term = compress(encoded_term, compressed)
        ln = len(encoded_term)
        if len(zlib_term) + 5 <= ln:
            # Compressed term should be smaller
            return b"\x83P" + _int4_pack(ln) + zlib_term
    return b"\x83" + encoded_term


def addSourceAddr(self, addr):
        """None means 'system default'"""
        try:
            self._multiInSocket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, self._makeMreq(addr))
        except socket.error:  # if 1 interface has more than 1 address, exception is raised for the second
            pass

        sock = self._createMulticastOutSocket(addr, self._observer.ttl)
        self._multiOutUniInSockets[addr] = sock
        self._poll.register(sock, select.POLLIN)


def _sendPendingMessages(self):
        """Method sleeps, if nothing to do"""
        if len(self._queue) == 0:
            time.sleep(0.1)
            return
        msg = self._queue.pop(0)
        if msg.canSend():
            self._sendMsg(msg)
            msg.refresh()
            if not (msg.isFinished()):
                self._queue.append(msg)
        else:
            self._queue.append(msg)
            time.sleep(0.01)

def _sendPendingMessages ( self ) : if len ( self . _queue ) == 0 : time . sleep ( 0.1 ) return msg = self . _queue . pop ( 0 ) if msg . canSend ( ) : self . _sendMsg ( msg ) msg . refresh ( ) if not ( msg . isFinished ( ) ) : self . _queue . append ( msg ) else : self . _queue . append ( msg ) time . sleep ( 0.01 )


def setRemoteServiceHelloCallback(self, cb, types=None, scopes=None):
        """Set callback, which will be called when new service appeared online
        and sent Hi message

        typesFilter and scopesFilter might be list of types and scopes.
        If filter is set, callback is called only for Hello messages,
        which match filter

        Set None to disable callback
        """
        self._remoteServiceHelloCallback = cb
        self._remoteServiceHelloCallbackTypesFilter = types
        self._remoteServiceHelloCallbackScopesFilter = scopes

def setRemoteServiceHelloCallback ( self , cb , types = None , scopes = None ) : self . _remoteServiceHelloCallback = cb self . _remoteServiceHelloCallbackTypesFilter = types self . _remoteServiceHelloCallbackScopesFilter = scopes

Set callback which will be called when new service appeared online and sent Hi message


def stop(self):
        'cleans up and stops the discovery server'

        self.clearRemoteServices()
        self.clearLocalServices()

        self._stopThreads()
        self._serverStarted = False

def stop ( self ) : self . clearRemoteServices ( ) self . clearLocalServices ( ) self . _stopThreads ( ) self . _serverStarted = False


def clearLocalServices(self):
        'send Bye messages for the services and remove them'

        for service in list(self._localServices.values()):
            self._sendBye(service)

        self._localServices.clear()

def clearLocalServices ( self ) : for service in list ( self . _localServices . values ( ) ) : self . _sendBye ( service ) self . _localServices . clear ( )


def searchServices(self, types=None, scopes=None, timeout=3):
        'search for services given the TYPES and SCOPES in a given TIMEOUT'

        if not self._serverStarted:
            raise Exception("Server not started")

        self._sendProbe(types, scopes)

        time.sleep(timeout)

        return self._filterServices(list(self._remoteServices.values()), types, scopes)

def
searchServices
(
self
,
types
=
,
scopes
=
,
timeout
=
3
)
:
if
not
self
.
_serverStarted
:
raise
Exception
(
"Server not started"
)
self
.
_sendProbe
(
types
,
scopes
)
time
.
sleep
(
timeout
)
return
self
.
_filterServices
(
list
(
self
.
_remoteServices
.
values
(
)
)
,
types
,
scopes
)


def createSOAPMessage(env):
    "construct a a raw SOAP XML string, given a prepared SoapEnvelope object"
    if env.getAction() == ACTION_PROBE:
        return createProbeMessage(env)
    if env.getAction() == ACTION_PROBE_MATCH:
        return createProbeMatchMessage(env)
    if env.getAction() == ACTION_RESOLVE:
        return createResolveMessage(env)
    if env.getAction() == ACTION_RESOLVE_MATCH:
        return createResolveMatchMessage(env)
    if env.getAction() == ACTION_HELLO:
        return createHelloMessage(env)
    if env.getAction() == ACTION_BYE:
        return createByeMessage(env)

def createSOAPMessage ( env ) : if env . getAction ( ) == ACTION_PROBE : return createProbeMessage ( env ) if env . getAction ( ) == ACTION_PROBE_MATCH : return createProbeMatchMessage ( env ) if env . getAction ( ) == ACTION_RESOLVE : return createResolveMessage ( env ) if env . getAction ( ) == ACTION_RESOLVE_MATCH : return createResolveMatchMessage ( env ) if env . getAction ( ) == ACTION_HELLO : return createHelloMessage ( env ) if env . getAction ( ) == ACTION_BYE : return createByeMessage ( env )

construct a a raw SOAP XML string given a prepared SoapEnvelope object


def discover(scope, loglevel, capture):
    "Discover systems using WS-Discovery"

    if loglevel:
        level = getattr(logging, loglevel, None)
        if not level:
           print("Invalid log level '%s'" % loglevel)
           return
        logger.setLevel(level)

    run(scope=scope, capture=capture)

def
discover
(
scope
,
loglevel
,
capture
)
:
if
loglevel
:
level
=
getattr
(
logging
,
loglevel
,
)
if
not
level
:
print
(
"Invalid log level '%s'"
%
loglevel
)
return
logger
.
setLevel
(
level
)
run
(
scope
=
scope
,
capture
=
capture
)


def get_tagged_item_manager(self):
        """Return the manager that handles the relation from this instance to the tagged_item class.
        If content_object on the tagged_item class is defined as a ParentalKey, this will be a
        DeferringRelatedManager which allows writing related objects without committing them
        to the database.
        """
        rel_name = self.through._meta.get_field('content_object').remote_field.get_accessor_name()
        return getattr(self.instance, rel_name)

def get_tagged_item_manager ( self ) : rel_name = self . through . _meta . get_field ( 'content_object' ) . remote_field . get_accessor_name ( ) return getattr ( self . instance , rel_name )

Return the manager that handles the relation from this instance to the tagged_item class . If content_object on the tagged_item class is defined as a ParentalKey this will be a DeferringRelatedManager which allows writing related objects without committing them to the database .


def get_all_child_relations(model):
    """
    Return a list of RelatedObject records for child relations of the given model,
    including ones attached to ancestors of the model
    """
    return [
        field for field in model._meta.get_fields()
        if isinstance(field.remote_field, ParentalKey)
    ]

def get_all_child_relations ( model ) : return [ field for field in model . _meta . get_fields ( ) if isinstance ( field . remote_field , ParentalKey ) ]

Return a list of RelatedObject records for child relations of the given model including ones attached to ancestors of the model


def get_all_child_m2m_relations(model):
    """
    Return a list of ParentalManyToManyFields on the given model,
    including ones attached to ancestors of the model
    """
    return [
        field for field in model._meta.get_fields()
        if isinstance(field, ParentalManyToManyField)
    ]

def get_all_child_m2m_relations ( model ) : return [ field for field in model . _meta . get_fields ( ) if isinstance ( field , ParentalManyToManyField ) ]

Return a list of ParentalManyToManyFields on the given model including ones attached to ancestors of the model


def save(self, **kwargs):
        """
        Save the model and commit all child relations.
        """
        child_relation_names = [rel.get_accessor_name() for rel in get_all_child_relations(self)]
        child_m2m_field_names = [field.name for field in get_all_child_m2m_relations(self)]

        update_fields = kwargs.pop('update_fields', None)
        if update_fields is None:
            real_update_fields = None
            relations_to_commit = child_relation_names
            m2m_fields_to_commit = child_m2m_field_names
        else:
            real_update_fields = []
            relations_to_commit = []
            m2m_fields_to_commit = []
            for field in update_fields:
                if field in child_relation_names:
                    relations_to_commit.append(field)
                elif field in child_m2m_field_names:
                    m2m_fields_to_commit.append(field)
                else:
                    real_update_fields.append(field)

        super(ClusterableModel, self).save(update_fields=real_update_fields, **kwargs)

        for relation in relations_to_commit:
            getattr(self, relation).commit()

        for field in m2m_fields_to_commit:
            getattr(self, field).commit()

def save ( self , * * kwargs ) : child_relation_names = [ rel . get_accessor_name ( ) for rel in get_all_child_relations ( self ) ] child_m2m_field_names = [ field . name for field in get_all_child_m2m_relations ( self ) ] update_fields = kwargs . pop ( 'update_fields' , None ) if update_fields is None : real_update_fields = None relations_to_commit = child_relation_names m2m_fields_to_commit = child_m2m_field_names else : real_update_fields = [ ] relations_to_commit = [ ] m2m_fields_to_commit = [ ] for field in update_fields : if field in child_relation_names : relations_to_commit . append ( field ) elif field in child_m2m_field_names : m2m_fields_to_commit . append ( field ) else : real_update_fields . append ( field ) super ( ClusterableModel , self ) . save ( update_fields = real_update_fields , * * kwargs ) for relation in relations_to_commit : getattr ( self , relation ) . commit ( ) for field in m2m_fields_to_commit : getattr ( self , field ) . commit ( )

Save the model and commit all child relations .


def from_serializable_data(cls, data, check_fks=True, strict_fks=False):
        """
        Build an instance of this model from the JSON-like structure passed in,
        recursing into related objects as required.
        If check_fks is true, it will check whether referenced foreign keys still
        exist in the database.
        - dangling foreign keys on related objects are dealt with by either nullifying the key or
        dropping the related object, according to the 'on_delete' setting.
        - dangling foreign keys on the base object will be nullified, unless strict_fks is true,
        in which case any dangling foreign keys with on_delete=CASCADE will cause None to be
        returned for the entire object.
        """
        obj = model_from_serializable_data(cls, data, check_fks=check_fks, strict_fks=strict_fks)
        if obj is None:
            return None

        child_relations = get_all_child_relations(cls)

        for rel in child_relations:
            rel_name = rel.get_accessor_name()
            try:
                child_data_list = data[rel_name]
            except KeyError:
                continue

            related_model = rel.related_model
            if hasattr(related_model, 'from_serializable_data'):
                children = [
                    related_model.from_serializable_data(child_data, check_fks=check_fks, strict_fks=True)
                    for child_data in child_data_list
                ]
            else:
                children = [
                    model_from_serializable_data(related_model, child_data, check_fks=check_fks, strict_fks=True)
                    for child_data in child_data_list
                ]

            children = filter(lambda child: child is not None, children)

            setattr(obj, rel_name, children)

        return obj

def from_serializable_data ( cls , data , check_fks = True , strict_fks = False ) : obj = model_from_serializable_data ( cls , data , check_fks = check_fks , strict_fks = strict_fks ) if obj is None : return None child_relations = get_all_child_relations ( cls ) for rel in child_relations : rel_name = rel . get_accessor_name ( ) try : child_data_list = data [ rel_name ] except KeyError : continue related_model = rel . related_model if hasattr ( related_model , 'from_serializable_data' ) : children = [ related_model . from_serializable_data ( child_data , check_fks = check_fks , strict_fks = True ) for child_data in child_data_list ] else : children = [ model_from_serializable_data ( related_model , child_data , check_fks = check_fks , strict_fks = True ) for child_data in child_data_list ] children = filter ( lambda child : child is not None , children ) setattr ( obj , rel_name , children ) return obj

Build an instance of this model from the JSON - like structure passed in recursing into related objects as required . If check_fks is true it will check whether referenced foreign keys still exist in the database . - dangling foreign keys on related objects are dealt with by either nullifying the key or dropping the related object according to the on_delete setting . - dangling foreign keys on the base object will be nullified unless strict_fks is true in which case any dangling foreign keys with on_delete = CASCADE will cause None to be returned for the entire object .


def validate_unique(self):
        '''This clean method will check for unique_together condition'''
        # Collect unique_checks and to run from all the forms.
        all_unique_checks = set()
        all_date_checks = set()
        forms_to_delete = self.deleted_forms
        valid_forms = [form for form in self.forms if form.is_valid() and form not in forms_to_delete]
        for form in valid_forms:
            unique_checks, date_checks = form.instance._get_unique_checks()
            all_unique_checks.update(unique_checks)
            all_date_checks.update(date_checks)

        errors = []
        # Do each of the unique checks (unique and unique_together)
        for uclass, unique_check in all_unique_checks:
            seen_data = set()
            for form in valid_forms:
                # Get the data for the set of fields that must be unique among the forms.
                row_data = (
                    field if field in self.unique_fields else form.cleaned_data[field]
                    for field in unique_check if field in form.cleaned_data
                )
                # Reduce Model instances to their primary key values
                row_data = tuple(d._get_pk_val() if hasattr(d, '_get_pk_val') else d
                                 for d in row_data)
                if row_data and None not in row_data:
                    # if we've already seen it then we have a uniqueness failure
                    if row_data in seen_data:
                        # poke error messages into the right places and mark
                        # the form as invalid
                        errors.append(self.get_unique_error_message(unique_check))
                        form._errors[NON_FIELD_ERRORS] = self.error_class([self.get_form_error()])
                        # remove the data from the cleaned_data dict since it was invalid
                        for field in unique_check:
                            if field in form.cleaned_data:
                                del form.cleaned_data[field]
                    # mark the data as seen
                    seen_data.add(row_data)

        if errors:
            raise ValidationError(errors)


def has_changed(self):
        """Return True if data differs from initial."""

        # Need to recurse over nested formsets so that the form is saved if there are changes
        # to child forms but not the parent
        if self.formsets:
            for formset in self.formsets.values():
                for form in formset.forms:
                    if form.has_changed():
                        return True
        return bool(self.changed_data)

Return True if data differs from initial .


def with_valid_checksum(self):
        # type: () -> Address
        """
        Returns the address with a valid checksum attached.
        """
        return Address(
            trytes=self.address + self._generate_checksum(),

            # Make sure to copy all of the ancillary attributes, too!
            balance=self.balance,
            key_index=self.key_index,
            security_level=self.security_level,
        )

Returns the address with a valid checksum attached .


def _generate_checksum(self):
        # type: () -> AddressChecksum
        """
        Generates the correct checksum for this address.
        """
        checksum_trits = []  # type: MutableSequence[int]

        sponge = Kerl()
        sponge.absorb(self.address.as_trits())
        sponge.squeeze(checksum_trits)

        checksum_length = AddressChecksum.LEN * TRITS_PER_TRYTE

        return AddressChecksum.from_trits(checksum_trits[-checksum_length:])

def
_generate_checksum
(
self
)
:
# type: () -> AddressChecksum
checksum_trits
=
[
]
# type: MutableSequence[int]
sponge
=
Kerl
(
)
sponge
.
absorb
(
self
.
address
.
as_trits
(
)
)
sponge
.
squeeze
(
checksum_trits
)
checksum_length
=
AddressChecksum
.
LEN
*
TRITS_PER_TRYTE
return
AddressChecksum
.
from_trits
(
checksum_trits
[
checksum_length
:
]
)

Generates the correct checksum for this address .


def parse_argv(self, argv=None):
        # type: (Optional[tuple]) -> dict
        """
        Parses arguments for the command.

        :param argv:
            Arguments to pass to the argument parser.
            If ``None``, defaults to ``sys.argv[1:]``.
        """
        arguments = vars(self.create_argument_parser().parse_args(argv))

        seed = None
        if self.requires_seed:
            seed_filepath = arguments.pop('seed_file')

            seed = (
                self.seed_from_filepath(seed_filepath)
                if seed_filepath
                else self.prompt_for_seed()
            )

        arguments['api'] = Iota(
            adapter=arguments.pop('uri'),
            seed=seed,
            testnet=arguments.pop('testnet'),
        )

        return arguments

def
parse_argv
(
self
,
argv
=
)
:
# type: (Optional[tuple]) -> dict
arguments
=
vars
(
self
.
create_argument_parser
(
)
.
parse_args
(
argv
)
)
seed
=
if
self
.
requires_seed
:
seed_filepath
=
arguments
.
pop
(
'seed_file'
)
seed
=
(
self
.
seed_from_filepath
(
seed_filepath
)
if
seed_filepath
else
self
.
prompt_for_seed
(
)
)
arguments
[
'api'
]
=
Iota
(
adapter
=
arguments
.
pop
(
'uri'
)
,
seed
=
seed
,
testnet
=
arguments
.
pop
(
'testnet'
)
,
)
return
arguments


def create_argument_parser(self):
        # type: () -> ArgumentParser
        """
        Returns the argument parser that will be used to interpret
        arguments and options from argv.
        """
        parser = ArgumentParser(
            description=self.__doc__,
            epilog='PyOTA v{version}'.format(version=__version__),
        )

        parser.add_argument(
            '--uri',
            type=text_type,
            default='http://localhost:14265/',

            help=(
                'URI of the node to connect to '
                '(defaults to http://localhost:14265/).'
            ),
        )

        if self.requires_seed:
            parser.add_argument(
                '--seed-file',
                type=text_type,
                dest='seed_file',

                help=(
                    'Path to a file containing your seed in cleartext. '
                    'If not provided, you will be prompted to enter '
                    'your seed via stdin.'
                ),
            )

        parser.add_argument(
            '--testnet',
            action='store_true',
            default=False,
            help='If set, use testnet settings (e.g., for PoW).',
        )

        return parser

Returns the argument parser that will be used to interpret arguments and options from argv .


def prompt_for_seed():
        # type: () -> Seed
        """
        Prompts the user to enter their seed via stdin.
        """
        seed = secure_input(
            'Enter seed and press return (typing will not be shown).\n'
            'If no seed is specified, a random one will be used instead.\n'
        )

        if isinstance(seed, text_type):
            seed = seed.encode('ascii')

        return Seed(seed) if seed else Seed.random()

Prompts the user to enter their seed via stdin .


def validate_signature_fragments(
        fragments,
        hash_,
        public_key,
        sponge_type=Kerl,
):
    # type: (Sequence[TryteString], Hash, TryteString, type) -> bool
    """
    Returns whether a sequence of signature fragments is valid.

    :param fragments:
      Sequence of signature fragments (usually
      :py:class:`iota.transaction.Fragment` instances).

    :param hash_:
      Hash used to generate the signature fragments (usually a
      :py:class:`iota.transaction.BundleHash` instance).

    :param public_key:
      The public key value used to verify the signature digest (usually a
      :py:class:`iota.types.Address` instance).

    :param sponge_type:
      The class used to create the cryptographic sponge (i.e., Curl or Kerl).
    """
    checksum = [0] * (HASH_LENGTH * len(fragments))
    normalized_hash = normalize(hash_)

    for i, fragment in enumerate(fragments):
        outer_sponge = sponge_type()

        # If there are more than 3 iterations, loop back around to the
        # start.
        normalized_chunk = normalized_hash[i % len(normalized_hash)]

        buffer = []
        for j, hash_trytes in enumerate(fragment.iter_chunks(Hash.LEN)):
            buffer = hash_trytes.as_trits()  # type: List[int]
            inner_sponge = sponge_type()

            # Note the sign flip compared to
            # :py;class:`SignatureFragmentGenerator`.
            for _ in range(13 + normalized_chunk[j]):
                inner_sponge.reset()
                inner_sponge.absorb(buffer)
                inner_sponge.squeeze(buffer)

            outer_sponge.absorb(buffer)

        outer_sponge.squeeze(buffer)
        checksum[i * HASH_LENGTH:(i + 1) * HASH_LENGTH] = buffer

    actual_public_key = [0] * HASH_LENGTH
    addy_sponge = sponge_type()
    addy_sponge.absorb(checksum)
    addy_sponge.squeeze(actual_public_key)

    return actual_public_key == public_key.as_trits()

Returns whether a sequence of signature fragments is valid .


def get_key(self, index, iterations):
        # type: (int, int) -> PrivateKey
        """
        Generates a single key.

        :param index:
            The key index.

        :param iterations:
            Number of transform iterations to apply to the key, also
            known as security level.
            Must be >= 1.

            Increasing this value makes key generation slower, but more
            resistant to brute-forcing.
        """
        return (
            self.get_keys(
                start=index,
                count=1,
                step=1,
                iterations=iterations,
            )[0]
        )

def
get_key
(
self
,
index
,
iterations
)
:
# type: (int, int) -> PrivateKey
return
(
self
.
get_keys
(
start
=
index
,
count
=
1
,
step
=
1
,
iterations
=
iterations
,
)
[
0
]
)


def get_key_for(self, address):
        """
        Generates the key associated with the specified address.

        Note that this method will generate the wrong key if the input
        address was generated from a different key!
        """
        return self.get_key(
            index=address.key_index,
            iterations=address.security_level,
        )

def get_key_for ( self , address ) : return self . get_key ( index = address . key_index , iterations = address . security_level , )

Generates the key associated with the specified address .


def create_iterator(self, start=0, step=1, security_level=1):
        # type: (int, int, int) -> KeyIterator
        """
        Creates a generator that can be used to progressively generate
        new keys.

        :param start:
            Starting index.

            Warning: This method may take awhile to reset if ``start``
            is a large number!

        :param step:
            Number of indexes to advance after each key.

            This value can be negative; the generator will exit if it
            reaches an index < 0.

            Warning: The generator may take awhile to advance between
            iterations if ``step`` is a large number!

        :param security_level:
            Number of _transform iterations to apply to each key.
            Must be >= 1.

            Increasing this value makes key generation slower, but more
            resistant to brute-forcing.
        """
        return KeyIterator(self.seed, start, step, security_level)

def
create_iterator
(
self
,
start
=
0
,
step
=
1
,
security_level
=
1
)
:
# type: (int, int, int) -> KeyIterator
return
KeyIterator
(
self
.
seed
,
start
,
step
,
security_level
)

Creates a generator that can be used to progressively generate new keys .


def _create_sponge(self, index):
        # type: (int) -> Kerl
        """
        Prepares the hash sponge for the generator.
        """
        seed = self.seed_as_trits[:]

        sponge = Kerl()
        sponge.absorb(add_trits(seed, trits_from_int(index)))

        # Squeeze all of the trits out of the sponge and re-absorb them.
        # Note that the sponge transforms several times per operation,
        # so this sequence is not as redundant as it looks at first
        # glance.
        sponge.squeeze(seed)
        sponge.reset()
        sponge.absorb(seed)

        return sponge

Prepares the hash sponge for the generator .


def absorb(self, trits, offset=0, length=None):
        # type: (Sequence[int], Optional[int], Optional[int]) -> None
        """
        Absorb trits into the sponge.

        :param trits:
            Sequence of trits to absorb.

        :param offset:
            Starting offset in ``trits``.

        :param length:
            Number of trits to absorb.  Defaults to ``len(trits)``.
        """
        pad = ((len(trits) % HASH_LENGTH) or HASH_LENGTH)
        trits += [0] * (HASH_LENGTH - pad)

        if length is None:
            length = len(trits)

        if length < 1:
            raise with_context(
                exc=ValueError('Invalid length passed to ``absorb``.'),

                context={
                    'trits': trits,
                    'offset': offset,
                    'length': length,
                },
            )

        # Copy trits from ``trits`` into internal state, one hash at a
        # time, transforming internal state in between hashes.
        while offset < length:
            start = offset
            stop = min(start + HASH_LENGTH, length)

            # Copy the next hash worth of trits to internal state.
            #
            # Note that we always copy the trits to the start of the
            # state. ``self._state`` is 3 hashes long, but only the
            # first hash is "public"; the other 2 are only accessible to
            # :py:meth:`_transform`.
            self._state[0:stop - start] = trits[start:stop]

            # Transform.
            self._transform()

            # Move on to the next hash.
            offset += HASH_LENGTH


def squeeze(self, trits, offset=0, length=HASH_LENGTH):
        # type: (MutableSequence[int], Optional[int], Optional[int]) -> None
        """
        Squeeze trits from the sponge.

        :param trits:
            Sequence that the squeezed trits will be copied to.
            Note: this object will be modified!

        :param offset:
            Starting offset in ``trits``.

        :param length:
            Number of trits to squeeze, default to ``HASH_LENGTH``
        """
        # Squeeze is kind of like the opposite of absorb; it copies
        # trits from internal state to the ``trits`` parameter, one hash
        # at a time, and transforming internal state in between hashes.
        #
        # However, only the first hash of the state is "public", so we
        # can simplify the implementation somewhat.

        # Ensure length can be mod by HASH_LENGTH
        if length % HASH_LENGTH != 0:
            raise with_context(
                exc=ValueError('Invalid length passed to ``squeeze`.'),

                context={
                    'trits': trits,
                    'offset': offset,
                    'length': length,
                })

        # Ensure that ``trits`` can hold at least one hash worth of
        # trits.
        trits.extend([0] * max(0, length - len(trits)))

        # Check trits with offset can handle hash length
        if len(trits) - offset < HASH_LENGTH:
            raise with_context(
                exc=ValueError('Invalid offset passed to ``squeeze``.'),

                context={
                    'trits': trits,
                    'offset': offset,
                    'length': length
                },
            )

        while length >= HASH_LENGTH:
            # Copy exactly one hash.
            trits[offset:offset + HASH_LENGTH] = self._state[0:HASH_LENGTH]

            # One hash worth of trits copied; now transform.
            self._transform()

            offset += HASH_LENGTH
            length -= HASH_LENGTH


def _transform(self):
        # type: () -> None
        """
        Transforms internal state.
        """
        # Copy some values locally so we can avoid global lookups in the
        # inner loop.
        #
        # References:
        #
        # - https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Local_Variables
        state_length = STATE_LENGTH
        truth_table = TRUTH_TABLE

        # Operate on a copy of ``self._state`` to eliminate dot lookups
        # in the inner loop.
        #
        # References:
        #
        # - https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Avoiding_dots...
        # - http://stackoverflow.com/a/2612990/
        prev_state = self._state[:]
        new_state = prev_state[:]

        # Note: This code looks significantly different from the C
        # implementation because it has been optimized to limit the
        # number of list item lookups (these are relatively slow in
        # Python).
        index = 0
        for _ in range(NUMBER_OF_ROUNDS):
            prev_trit = prev_state[index]

            for pos in range(state_length):
                index += (364 if index < 365 else -365)

                new_trit = prev_state[index]

                new_state[pos] = truth_table[prev_trit + (3 * new_trit) + 4]

                prev_trit = new_trit

            prev_state = new_state
            new_state = new_state[:]

        self._state = new_state


def get_digests(
            self,
            index=0,
            count=1,
            security_level=AddressGenerator.DEFAULT_SECURITY_LEVEL,
    ):
        # type: (int, int, int) -> dict
        """
        Generates one or more key digests from the seed.

        Digests are safe to share; use them to generate multisig
        addresses.

        :param index:
            The starting key index.

        :param count:
            Number of digests to generate.

        :param security_level:
            Number of iterations to use when generating new addresses.

            Larger values take longer, but the resulting signatures are
            more secure.

            This value must be between 1 and 3, inclusive.

        :return:
            Dict with the following items::

                {
                    'digests': List[Digest],
                        Always contains a list, even if only one digest
                        was generated.
                }
        """
        return commands.GetDigestsCommand(self.adapter)(
            seed=self.seed,
            index=index,
            count=count,
            securityLevel=security_level,
        )

def
get_digests
(
self
,
index
=
0
,
count
=
1
,
security_level
=
AddressGenerator
.
DEFAULT_SECURITY_LEVEL
,
)
:
# type: (int, int, int) -> dict
return
commands
.
GetDigestsCommand
(
self
.
adapter
)
(
seed
=
self
.
seed
,
index
=
index
,
count
=
count
,
securityLevel
=
security_level
,
)

Generates one or more key digests from the seed .


def get_private_keys(
            self,
            index=0,
            count=1,
            security_level=AddressGenerator.DEFAULT_SECURITY_LEVEL,
    ):
        # type: (int, int, int) -> dict
        """
        Generates one or more private keys from the seed.

        As the name implies, private keys should not be shared.
        However, in a few cases it may be necessary (e.g., for M-of-N
        transactions).

        :param index:
            The starting key index.

        :param count:
            Number of keys to generate.

        :param security_level:
            Number of iterations to use when generating new keys.

            Larger values take longer, but the resulting signatures are
            more secure.

            This value must be between 1 and 3, inclusive.

        :return:
            Dict with the following items::

                {
                    'keys': List[PrivateKey],
                        Always contains a list, even if only one key was
                        generated.
                }

        References:

        - :py:class:`iota.crypto.signing.KeyGenerator`
        - https://github.com/iotaledger/wiki/blob/master/multisigs.md#how-m-of-n-works
        """
        return commands.GetPrivateKeysCommand(self.adapter)(
            seed=self.seed,
            index=index,
            count=count,
            securityLevel=security_level,
        )

def
get_private_keys
(
self
,
index
=
0
,
count
=
1
,
security_level
=
AddressGenerator
.
DEFAULT_SECURITY_LEVEL
,
)
:
# type: (int, int, int) -> dict
return
commands
.
GetPrivateKeysCommand
(
self
.
adapter
)
(
seed
=
self
.
seed
,
index
=
index
,
count
=
count
,
securityLevel
=
security_level
,
)

Generates one or more private keys from the seed .


def prepare_multisig_transfer(
            self,
            transfers,  # type: Iterable[ProposedTransaction]
            multisig_input,  # type: MultisigAddress
            change_address=None,  # type: Optional[Address]
    ):
        # type: (...) -> dict
        """
        Prepares a bundle that authorizes the spending of IOTAs from a
        multisig address.

        .. note::
            This method is used exclusively to spend IOTAs from a
            multisig address.

            If you want to spend IOTAs from non-multisig addresses, or
            if you want to create 0-value transfers (i.e., that don't
            require inputs), use
            :py:meth:`iota.api.Iota.prepare_transfer` instead.

        :param transfers:
            Transaction objects to prepare.

            .. important::
                Must include at least one transaction that spends IOTAs
                (i.e., has a nonzero ``value``).  If you want to prepare
                a bundle that does not spend any IOTAs, use
                :py:meth:`iota.api.prepare_transfer` instead.

        :param multisig_input:
            The multisig address to use as the input for the transfers.

            .. note::
                This method only supports creating a bundle with a
                single multisig input.

                If you would like to spend from multiple multisig
                addresses in the same bundle, create the
                :py:class:`iota.multisig.transaction.ProposedMultisigBundle`
                object manually.

        :param change_address:
            If inputs are provided, any unspent amount will be sent to
            this address.

            If the bundle has no unspent inputs, ``change_address` is
            ignored.

            .. important::
                Unlike :py:meth:`iota.api.Iota.prepare_transfer`, this
                method will NOT generate a change address automatically.
                If there are unspent inputs and ``change_address`` is
                empty, an exception will be raised.

                This is because multisig transactions typically involve
                multiple individuals, and it would be unfair to the
                participants if we generated a change address
                automatically using the seed of whoever happened to run
                the ``prepare_multisig_transfer`` method!

                .. danger::
                    Note that this protective measure is not a
                    substitute for due diligence!

                    Always verify the details of every transaction in a
                    bundle (including the change transaction) before
                    signing the input(s)!

        :return:
            Dict containing the following values::

                {
                    'trytes': List[TransactionTrytes],
                        Finalized bundle, as trytes.
                        The input transactions are not signed.
                }

          In order to authorize the spending of IOTAs from the multisig
          input, you must generate the correct private keys and invoke
          the :py:meth:`iota.crypto.types.PrivateKey.sign_input_at`
          method for each key, in the correct order.

          Once the correct signatures are applied, you can then perform
          proof of work (``attachToTangle``) and broadcast the bundle
          using :py:meth:`iota.api.Iota.send_trytes`.
        """
        return commands.PrepareMultisigTransferCommand(self.adapter)(
            changeAddress=change_address,
            multisigInput=multisig_input,
            transfers=transfers,
        )

def
prepare_multisig_transfer
(
self
,
transfers
,
# type: Iterable[ProposedTransaction]
multisig_input
,
# type: MultisigAddress
change_address
=
,
# type: Optional[Address]
)
:
# type: (...) -> dict
return
commands
.
PrepareMultisigTransferCommand
(
self
.
adapter
)
(
changeAddress
=
change_address
,
multisigInput
=
multisig_input
,
transfers
=
transfers
,
)

Prepares a bundle that authorizes the spending of IOTAs from a multisig address .


def add_trits(left, right):
    # type: (Sequence[int], Sequence[int]) -> List[int]
    """
    Adds two sequences of trits together.

    The result is a list of trits equal in length to the longer of the
    two sequences.

    .. note::
        Overflow is possible.

        For example, ``add_trits([1], [1])`` returns ``[-1]``.
    """
    target_len = max(len(left), len(right))

    res = [0] * target_len
    left += [0] * (target_len - len(left))
    right += [0] * (target_len - len(right))

    carry = 0
    for i in range(len(res)):
        res[i], carry = _full_add_trits(left[i], right[i], carry)

    return res


def trits_from_int(n, pad=1):
    # type: (int, Optional[int]) -> List[int]
    """
    Returns a trit representation of an integer value.

    :param n:
        Integer value to convert.

    :param pad:
        Ensure the result has at least this many trits.

    References:

    - https://dev.to/buntine/the-balanced-ternary-machines-of-soviet-russia
    - https://en.wikipedia.org/wiki/Balanced_ternary
    - https://rosettacode.org/wiki/Balanced_ternary#Python
    """
    if n == 0:
        trits = []
    else:
        quotient, remainder = divmod(n, 3)

        if remainder == 2:
            # Lend 1 to the next place so we can make this trit
            # negative.
            quotient += 1
            remainder = -1

        trits = [remainder] + trits_from_int(quotient, pad=0)

    if pad:
        trits += [0] * max(0, pad - len(trits))

    return trits

Returns a trit representation of an integer value .


def _add_trits(left, right):
    # type: (int, int) -> int
    """
    Adds two individual trits together.

    The result is always a single trit.
    """
    res = left + right
    return res if -2 < res < 2 else (res < 0) - (res > 0)

def
_add_trits
(
left
,
right
)
:
# type: (int, int) -> int
res
=
left
+
right
return
res
if
2
<
res
<
2
else
(
res
<
0
)
(
res
>
0
)


def _full_add_trits(left, right, carry):
    # type: (int, int, int) -> Tuple[int, int]
    """
    Adds two trits together, with support for a carry trit.
    """
    sum_both = _add_trits(left, right)
    cons_left = _cons_trits(left, right)
    cons_right = _cons_trits(sum_both, carry)

    return _add_trits(sum_both, carry), _any_trits(cons_left, cons_right)

Adds two trits together with support for a carry trit .


def output_seed(seed):
    # type: (Seed) -> None
    """
    Outputs the user's seed to stdout, along with lots of warnings
    about security.
    """
    print(
        'WARNING: Anyone who has your seed can spend your IOTAs! '
        'Clear the screen after recording your seed!'
    )
    compat.input('')
    print('Your seed is:')
    print('')
    print(binary_type(seed).decode('ascii'))
    print('')

    print(
        'Clear the screen to prevent shoulder surfing, '
        'and press return to continue.'
    )
    print('https://en.wikipedia.org/wiki/Shoulder_surfing_(computer_security)')
    compat.input('')

Outputs the user s seed to stdout along with lots of warnings about security .


def find_transactions(
            self,
            bundles=None,  # type: Optional[Iterable[BundleHash]]
            addresses=None,  # type: Optional[Iterable[Address]]
            tags=None,  # type: Optional[Iterable[Tag]]
            approvees=None,  # type: Optional[Iterable[TransactionHash]]
    ):
        # type: (...) -> dict
        """
        Find the transactions which match the specified input and
        return.

        All input values are lists, for which a list of return values
        (transaction hashes), in the same order, is returned for all
        individual elements.

        Using multiple of these input fields returns the intersection of
        the values.

        :param bundles:
          List of bundle IDs.

        :param addresses:
            List of addresses.

        :param tags:
            List of tags.

        :param approvees:
            List of approvee transaction IDs.

        References:

        - https://iota.readme.io/docs/findtransactions
        """
        return core.FindTransactionsCommand(self.adapter)(
            bundles=bundles,
            addresses=addresses,
            tags=tags,
            approvees=approvees,
        )

Find the transactions which match the specified input and return .