<commit_before># -*- coding: utf-8 -*-
import socket
from contextlib import contextmanager

import stun
from ethereum import slogging as logging


log = logging.getLogger(__name__)


@contextmanager
def stun_socket(
    source_ip='0.0.0.0',
    source_port=4200,
    stun_host=None,
    stun_port=3478
):
    with open_bare_socket(source_ip=source_ip, source_port=source_port) as sock:
        sock.settimeout(2)
        log.debug("Initiating STUN")
        nat_type, nat = stun.get_nat_type(
            sock,
            source_ip,
            source_port,
            stun_host=stun_host,
            stun_port=stun_port
        )
        external_ip = nat['ExternalIP']
        if isinstance(external_ip, tuple):
            external_ip = external_ip[0]
        external_port = nat['ExternalPort']
        log.debug("STUN-socket ready:",
                  external_ip=external_ip[0] or 'unknown',  # for some reason 'Test3' returns 'None' in some cases
                  external_port=external_port or 'unknown',
                  nat_type=nat_type,
                  nat=nat,
                  internal_ip=sock.getsockname()[0],
                  internal_port=sock.getsockname()[1],
        )
        nat['type'] = nat_type
        yield (sock, external_ip, external_port, nat)


@contextmanager
def open_bare_socket(
    source_ip='0.0.0.0',
    source_port=42000
):
    sock = socket.socket(
        socket.AF_INET,  # Internet
        socket.SOCK_DGRAM  # UDP
    )

    sock.setsockopt(
        socket.SOL_SOCKET,
        socket.SO_REUSEADDR,
        1
    )
    sock.bind(
        (source_ip, source_port)
    )
    log.debug("opened socket",
        ip=sock.getsockname()[0],
        port=sock.getsockname()[1],
    )
    yield sock
    sock.close()
<commit_msg>Introduce Exception for failed STUN<commit_after># -*- coding: utf-8 -*-
import socket
from contextlib import contextmanager

import stun
from ethereum import slogging as logging


log = logging.getLogger(__name__)


class STUNUnavailableException(Exception):
    pass


@contextmanager
def stun_socket(
    source_ip='0.0.0.0',
    source_port=4200,
    stun_host=None,
    stun_port=3478
):
    with open_bare_socket(source_ip=source_ip, source_port=source_port) as sock:
        sock.settimeout(2)
        log.debug('Initiating STUN')
        nat_type, nat = stun.get_nat_type(
            sock,
            source_ip,
            source_port,
            stun_host=stun_host,
            stun_port=stun_port
        )
        external_ip = nat['ExternalIP']
        if isinstance(external_ip, tuple):
            external_ip = external_ip[0]
        if external_ip is None:
            raise STUNUnavailableException()
        external_port = nat['ExternalPort']
        log.debug(
            'STUN-socket ready:',
            # for some reason 'Test3' returns 'None' in some cases
            external_ip=external_ip[0] or 'unknown',
            external_port=external_port or 'unknown',
            nat_type=nat_type,
            nat=nat,
            internal_ip=sock.getsockname()[0],
            internal_port=sock.getsockname()[1],
        )
        nat['type'] = nat_type
        yield (sock, external_ip, external_port, nat)


@contextmanager
def open_bare_socket(
    source_ip='0.0.0.0',
    source_port=42000
):
    sock = socket.socket(
        socket.AF_INET,  # Internet
        socket.SOCK_DGRAM  # UDP
    )

    sock.setsockopt(
        socket.SOL_SOCKET,
        socket.SO_REUSEADDR,
        1
    )
    sock.bind(
        (source_ip, source_port)
    )
    log.debug(
        'opened socket',
        ip=sock.getsockname()[0],
        port=sock.getsockname()[1],
    )
    yield sock
    sock.close()

{'fraction_non_alphanumeric': 0.10005408328826393, 'fraction_numerical': 0.0167658193618172, 'mean_word_length': 2.1696658097686377, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2614151', 'n_tokens_mistral': 1215, 'n_tokens_neox': 1167, 'n_words': 223}