<commit_before>import json
import os
import platform
import socket
import ssl
import subprocess
import time
from http.client import HTTPSConnection
from json import JSONDecodeError
from os import PathLike
from typing import IO, Any, Callable, List, Optional, Tuple, Union
from urllib.parse import urlunparse

import structlog
from mirakuru.base import ENV_UUID
from mirakuru.exceptions import AlreadyRunning, ProcessExitedWithError
from mirakuru.http import HTTPConnection, HTTPException, HTTPExecutor as MiHTTPExecutor

T_IO_OR_INT = Union[IO, int]

log = structlog.get_logger(__name__)


class HTTPExecutor(MiHTTPExecutor):
    """ Subclass off mirakuru.HTTPExecutor, which allows other methods than HEAD """

    def __init__(
            self,
            command: Union[str, List[str]],
            url: str,
            status: str = r'^2\d\d$',
            method: str = 'HEAD',
            io: Optional[Union[int, Tuple[T_IO_OR_INT, T_IO_OR_INT, T_IO_OR_INT]]] = None,
            cwd: Union[str, PathLike] = None,
            verify_tls: bool = True,
            **kwargs,
    ):
        super().__init__(command, url, status, **kwargs)
        self.method = method
        self.stdio = io
        self.cwd = cwd
        self.verify_tls = verify_tls

    def after_start_check(self):
        """ Check if defined URL returns expected status to a <method> request. """
        try:
            if self.url.scheme == 'http':
                conn = HTTPConnection(self.host, self.port)
            elif self.url.scheme == 'https':
                ssl_context = None
                if not self.verify_tls:
                    ssl_context = ssl._create_unverified_context()
                conn = HTTPSConnection(
                    self.host,
                    self.port,
                    context=ssl_context,
                )
            else:
                raise ValueError(f'Unsupported URL scheme: "{self.url.scheme}"')

            self._send_request(conn)
            response = conn.getresponse()
            status = str(response.status)

            if not self._validate_response(response):
                return False

            if status == self.status or self.status_re.match(status):
                conn.close()
                return True

        except (HTTPException, socket.timeout, socket.error) as ex:
            log.warning('Executor process not healthy', command=self.command, error=ex)
            time.sleep(.05)
            return False

        return False

    def start(self):
        """
        Reimplements Executor and SimpleExecutor start to allow setting stdin/stdout/stderr/cwd

        It may break input/output/communicate, but will ensure child output redirects won't
        break parent process by filling the PIPE.
        Also, catches ProcessExitedWithError and raise FileNotFoundError if exitcode was 127
        """
        if self.pre_start_check():
            # Some other executor (or process) is running with same config:<commit_msg>Make tests node executor logging less threatening<commit_after>import json
import os
import platform
import socket
import ssl
import subprocess
import time
from http.client import HTTPSConnection
from json import JSONDecodeError
from os import PathLike
from typing import IO, Any, Callable, List, Optional, Tuple, Union
from urllib.parse import urlunparse

import structlog
from mirakuru.base import ENV_UUID
from mirakuru.exceptions import AlreadyRunning, ProcessExitedWithError
from mirakuru.http import HTTPConnection, HTTPException, HTTPExecutor as MiHTTPExecutor

T_IO_OR_INT = Union[IO, int]

log = structlog.get_logger(__name__)


class HTTPExecutor(MiHTTPExecutor):
    """ Subclass off mirakuru.HTTPExecutor, which allows other methods than HEAD """

    def __init__(
            self,
            command: Union[str, List[str]],
            url: str,
            status: str = r'^2\d\d$',
            method: str = 'HEAD',
            io: Optional[Union[int, Tuple[T_IO_OR_INT, T_IO_OR_INT, T_IO_OR_INT]]] = None,
            cwd: Union[str, PathLike] = None,
            verify_tls: bool = True,
            **kwargs,
    ):
        super().__init__(command, url, status, **kwargs)
        self.method = method
        self.stdio = io
        self.cwd = cwd
        self.verify_tls = verify_tls

    def after_start_check(self):
        """ Check if defined URL returns expected status to a <method> request. """
        try:
            if self.url.scheme == 'http':
                conn = HTTPConnection(self.host, self.port)
            elif self.url.scheme == 'https':
                ssl_context = None
                if not self.verify_tls:
                    ssl_context = ssl._create_unverified_context()
                conn = HTTPSConnection(
                    self.host,
                    self.port,
                    context=ssl_context,
                )
            else:
                raise ValueError(f'Unsupported URL scheme: "{self.url.scheme}"')

            self._send_request(conn)
            response = conn.getresponse()
            status = str(response.status)

            if not self._validate_response(response):
                return False

            if status == self.status or self.status_re.match(status):
                conn.close()
                return True

        except (HTTPException, socket.timeout, socket.error) as ex:
            log.debug('Executor process not healthy yet', command=self.command, error=ex)
            time.sleep(.05)
            return False

        return False

    def start(self):
        """
        Reimplements Executor and SimpleExecutor start to allow setting stdin/stdout/stderr/cwd

        It may break input/output/communicate, but will ensure child output redirects won't
        break parent process by filling the PIPE.
        Also, catches ProcessExitedWithError and raise FileNotFoundError if exitcode was 127
        """
        if self.pre_start_check():
            # Some other executor (or process) is running with same config:
{'fraction_non_alphanumeric': 0.07903439153439154, 'fraction_numerical': 0.001984126984126984, 'mean_word_length': 2.150520833333333, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '7350841', 'n_tokens_mistral': 1637, 'n_tokens_neox': 1568, 'n_words': 490}