import warnings
from typing import Optional, Union

import numpy as np
from ecos import solve
from scipy import sparse as spa

from ..conversions import (
    linear_from_box_inequalities,
    socp_from_qp,
    split_dual_linear_box,
)
from ..exceptions import ProblemError
from ..problem import Problem
from ..solution import Solution

__exit_flag_meaning__ = {
    0: "OPTIMAL",
    1: "PINF: found certificate of primal infeasibility",
    2: "DING: found certificate of dual infeasibility",
    10: "INACC_OFFSET: inaccurate results",
    11: "PINF_INACC: found inaccurate certificate of primal infeasibility",
    12: "DING_INACC: found inaccurate certificate of dual infeasibility",
    -1: "MAXIT: maximum number of iterations reached",
    -2: "NUMERICS: search direction is unreliable",
    -3: "OUTCONE: primal or dual variables got outside of cone",
    -4: "SIGINT: solver interrupted",
    -7: "FATAL: unknown solver problem",
}

def ecos_solve_problem(
    problem: Problem,
    initvals: Optional[np.ndarray] = None,
    verbose: bool = False,
    **kwargs,
) -> Solution:
    """Solve a quadratic program using ECOS.

    Parameters
    ----------
    P :
        Primal quadratic cost matrix.
    q :
        Primal quadratic cost vector.
    G :
        Linear inequality constraint matrix.
    h :
        Linear inequality constraint vector.
    A :
        Linear equality constraint matrix.
    b :
        Linear equality constraint vector.
    initvals :
        Warm-start guess vector (not used).
    verbose :
        Set to `True` to print out extra information.

    Returns
    -------
    :
        Solution to the QP, if found, otherwise ``None``.

    Raises
    ------
    ProblemError :
        If inequality constraints contain infinite values that the solver
        doesn't handle.

    ValueError :
        If the cost matrix is not positive definite.

    Notes
    -----
    All other keyword arguments are forwarded as options to the ECOS solver.
    For instance, you can call ``qpswift_solve_qp(P, q, G, h, abstol=1e-5)``.

    For a quick overview, the solver accepts the following settings:

    .. list-table::
       :widths: 30 70
       :header-rows: 1

       * - Name
         - Effect
       * - ``feastol``
         -  Tolerance on the primal and dual residual.
       * - ``abstol``
         -  Absolute tolerance on the duality gap.
       * - ``reltol``
         -  Relative tolerance on the duality gap.
       * - ``feastol_inacc``
         -  Tolerance on the primal and dual residual if reduced precisions.
       * - ``abstol_inacc``
         - Absolute tolerance on the duality gap if reduced precision.
       * - ``reltolL_inacc``
         - Relative tolerance on the duality gap if reduced precision.
       * - ``max_iters``
         - Maximum numer of iterations.
       * - ``nitref``
         - Number of iterative refinement steps.

    See the `ECOS Python wrapper documentation
    <https://github.com/embotech/ecos-python#calling-ecos-from-python>`_ for
    more details. You can also check out [tolerances]_ for a primer on
    primal-dual residuals or the duality gap.
    """
    if initvals is not None:
        warnings.warn("warm-start values are ignored by this wrapper")
    P, q, G, h, A, b, lb, ub = problem.unpack()
    if lb is not None or ub is not None:
        G, h = linear_from_box_inequalities(
            G, h, lb, ub, use_sparse=problem.has_sparse
        )
    kwargs.update({"verbose": verbose})
    c_socp, G_socp, h_socp, dims = socp_from_qp(P, q, G, h)
    if A is not None:
        A_socp = spa.hstack([A, spa.csc_matrix((A.shape[0], 1))], format="csc")
        result = solve(c_socp, G_socp, h_socp, dims, A_socp, b, **kwargs)
    else:
        result = solve(c_socp, G_socp, h_socp, dims, **kwargs)
    flag = result["info"]["exitFlag"]
    solution = Solution(problem)
    solution.extras = result["info"]
    solution.found = flag == 0
    if not solution.found:
        if h is not None and not np.isfinite(h).all():
            raise ProblemError(
                "ECOS does not handle infinite values in inequality vectors, "
                "try clipping them to a finite value suitable to your problem"
            )
        meaning = __exit_flag_meaning__.get(flag, "unknown exit flag")
        warnings.warn(f"ECOS returned exit flag {flag} ({meaning})")
    solution.x = result["x"][:-1]
    if A is not None:
        solution.y = result["y"]
    if G is not None:
        z_ecos = result["z"][: G.shape[0]]
        z, z_box = split_dual_linear_box(z_ecos, lb, ub)
        solution.z = z
        solution.z_box = z_box
    return solution

def ecos_solve_qp(
    P: Union[np.ndarray, spa.csc_matrix],
    q: np.ndarray,
    G: Optional[Union[np.ndarray, spa.csc_matrix]] = None,
    h: Optional[np.ndarray] = None,
    A: Optional[Union[np.ndarray, spa.csc_matrix]] = None,
    b: Optional[np.ndarray] = None,
    lb: Optional[np.ndarray] = None,
    ub: Optional[np.ndarray] = None,
    initvals: Optional[np.ndarray] = None,
    verbose: bool = False,
    **kwargs,
) -> Optional[np.ndarray]:
    r"""Solve a quadratic program using ECOS.

    The quadratic program is defined as:

    .. math::

        \begin{split}\begin{array}{ll}
            \underset{x}{\mbox{minimize}} &
                \frac{1}{2} x^T P x + q^T x \\
            \mbox{subject to}
                & G x \leq h                \\
                & A x = b
        \end{array}\end{split}

    It is solved using `ECOS <https://github.com/embotech/ecos>`__.

    Parameters
    ----------
    P :
        Primal quadratic cost matrix.
    q :
        Primal quadratic cost vector.
    G :
        Linear inequality constraint matrix.
    h :
        Linear inequality constraint vector.
    A :
        Linear equality constraint matrix.
    b :
        Linear equality constraint vector.
    initvals :
        Warm-start guess vector (not used).
    verbose :
        Set to `True` to print out extra information.

    Returns
    -------
    :
        Solution to the QP, if found, otherwise ``None``.

    Notes
    -----
    All other keyword arguments are forwarded as options to the ECOS solver.
    For instance, you can call ``qpswift_solve_qp(P, q, G, h, abstol=1e-5)``.

    For a quick overview, the solver accepts the following settings:

    .. list-table::
       :widths: 30 70
       :header-rows: 1

       * - Name
         - Effect
       * - ``feastol``
         -  Tolerance on the primal and dual residual.
       * - ``abstol``
         -  Absolute tolerance on the duality gap.
       * - ``reltol``
         -  Relative tolerance on the duality gap.
       * - ``feastol_inacc``
         -  Tolerance on the primal and dual residual if reduced precisions.
       * - ``abstol_inacc``
         - Absolute tolerance on the duality gap if reduced precision.
       * - ``reltolL_inacc``
         - Relative tolerance on the duality gap if reduced precision.
       * - ``max_iters``
         - Maximum numer of iterations.
       * - ``nitref``
         - Number of iterative refinement steps.

    See the `ECOS Python wrapper documentation
    <https://github.com/embotech/ecos-python#calling-ecos-from-python>`_ for
    more details. You can also check out [tolerances]_ for a primer on
    primal-dual residuals or the duality gap.
    """
    problem = Problem(P, q, G, h, A, b, lb, ub)
    solution = ecos_solve_problem(problem, initvals, verbose, **kwargs)
    return solution.x if solution.found else None


from re import findall
from urllib import urlopen as uReq
from bs4 import BeautifulSoup as soup
import random

firstNameProto = ''

def sex():                      # returns the url extension for males and females
    choice = random.randrange(0,3)
    if choice == 0:
        return '/gender/masculine'
    elif choice == 1:
        return '/gender/feminine'
    else:
        return '/gender/unisex'

def getCountry(url):            # gets a country
    # open connection, grab the page
    uClient = uReq(url)
    page_html = uClient.read()
    uClient.close()
    # html parser
    page_soup = soup(page_html, "html.parser")
    # return container name and sorts out country names
    containerName = page_soup.findAll("span",{"class":"heavy"})
    countryName = findall(r'/names/usage/(.*?)">',str(containerName))
    return(countryName[random.randrange(0,len(countryName))])

def pickUrl(sex, country):      # page url
    my_url = '{}{}{}{}'.format('https://www.behindthename.com/names',sex,'/usage/',country)
    return my_url

def findNumPages(url):          # check the url to see if there are multiple pages
    # a reference to the current url to use when finding values for the number of pages
    # eg:value="/names/usage/english/13">page 13</option></select>
    container_page_ref = (url[30:]) + '/'
    # open connection, grab the page
    uClient = uReq(url)
    page_html = uClient.read()
    uClient.close()
    # html parser
    page_soup = soup(page_html, "html.parser")
    # grabes each item and finds the largest number
    containersPage = str(page_soup.find("select",{"name": "page"}))
    page_num = findall(r'{0}(.*?)">page '.format(container_page_ref), containersPage)
    #checks len of list before conversion to integers
    if len(page_num) > 0:
        page_num_max = (max(map (int, page_num)))
        return page_num_max
    else:
        return ''

def findRandPage(pages):        # return a random number for the page if there are multiple pages
    if pages == '' or pages < 2:
        return my_url
    else:
        return my_url + '/' + str(random.randrange(2, urlPages + 1))

def firstNameLst(url):          # returns a list of first names
    # open connection, grab the page
    uClient = uReq(url)
    page_html = uClient.read()
    uClient.close()
    # html parser
    page_soup = soup(page_html, "html.parser")
    # grabs each item in the class called browsename
    # searches out the names and creates a list we can use to draw from randomly
    containersName = page_soup.findAll("div",{"class":"browsename"})
    to_string_name = ''
    if len(containersName) == 0:
        return ''
    else:
        for items in range(0, len(containersName)):
            to_string_name += str((containersName[items].b.a))
    first_name = findall(r'">(.*?)',to_string_name)
    return first_name[random.randrange(0, len(first_name)) ]

def checkFirstName(extraStr):   # checks the first name for any extra characters (2) or -2-
    if extraStr[:-1] == '-':
        return extraStr[:-2]
    else:
        return extraStr

def mainFirstName():
    global firstNameProto
    firstNameProto = ''
    while firstNameProto == '':
        global sex
        global country
        global my_url
        global urlPages
        global searchPage
        sex = sex()
        country = getCountry('https://www.behindthename.com/names/list')
        my_url = pickUrl(sex, country)
        urlPages = findNumPages(my_url)
        searchPage = findRandPage(urlPages)
        firstNameProto = firstNameLst(searchPage) # if nothing is found try again
    global firstName
    firstName = checkFirstName(firstNameProto)
    return firstName

#sex = sex()
#print(sex)
#country = getCountry('https://www.behindthename.com/names/list')
#print(country)
#my_url = pickUrl(sex, country)
#print(my_url)
#urlPages = findNumPages(my_url)
#print(urlPages)
#searchPage = findRandPage(urlPages)
#print(searchPage)
#firstNameProto = firstNameLst(searchPage)
#print(firstNameProto)
#firstName = checkFirstName(firstNameProto)
#print(firstName)
randomFirstName = mainFirstName()

print(randomFirstName.capitalize() + ' -' + sex.replace('/',' ') + ' - country : ' + country)


import random

import pygame

from pygame.sprite import Group
from field import Field
from cell import Cell

pygame.init()

WIDTH = 425
HEIGHT = 425

max_step = 320
min_step = 5

screen = pygame.display.set_mode((WIDTH, HEIGHT))  # (ширина, высота)
pygame.display.set_caption("2048")
icon = pygame.image.load("2048.png")
pygame.display.set_icon(icon)
screen.fill("#7179C2")

field_cells = Group()
cells = Group()

# cell = Cell(screen, random.randrange(5, round(WIDTH)-26, 105), random.randrange(5, round(HEIGHT) - 26, 105), 2)
# cells.add(cell)

def cell_spawn(field_cells):
    lists = field_cells.sprites()
    random.shuffle(lists)
    for f_cells in lists:
        if not f_cells.filling:   #* не занято?
            cell = Cell(screen, f_cells.rect.x, f_cells.rect.y, 2)
            cells.add(cell)
            f_cells.filling = True
            break

def field_cell_init():
    for i in range(0, round(WIDTH)-26, 105):
        for j in range(0, round(HEIGHT) - 26, 105):
            f = Field(screen, i, j)
            field_cells.add(f)

def control():
    #* Функция управления игрой.
    #* Сдержит алгоритм соединения либо движения ячеек
    pass

def move_all_cell(teg, cells, field_cells):
    step_len = 0
    for cell in cells:
        if teg == "up":
            cell_pos = cell.get_pos()
            step_len = cell_pos[1] - 5
        elif teg == "down":
            cell_pos = cell.get_pos()
            step_len = 320 - cell_pos[1]
        elif teg == "right":
            cell_pos = cell.get_pos()
            step_len = 320 - cell_pos[0]
        elif teg == "left":
            cell_pos = cell.get_pos()
            step_len = cell_pos[0] - 5
        cell.move_cell(teg, step_len)

field_cell_init()
field_cells.draw(screen)

while True:

    for events in pygame.event.get():
        if events.type == pygame.QUIT:
            exit()
        if events.type == pygame.KEYDOWN:
            if events.key == pygame.K_w:
                cell_spawn(field_cells)
                move_all_cell("up", cells, field_cells)
            elif events.key == pygame.K_s:
                cell_spawn(field_cells)
                move_all_cell("down", cells, field_cells)
            elif events.key == pygame.K_a:
                cell_spawn(field_cells)
                move_all_cell("left", cells, field_cells)
            elif events.key == pygame.K_d:
                cell_spawn(field_cells)
                move_all_cell("right", cells, field_cells)

    field_cells.draw(screen)
    cells.draw(screen)

    pygame.display.update()


"""
Develop integration packages for LangChain.
"""

import re
import shutil
import subprocess
from pathlib import Path
from typing import Optional

import typer
from typing_extensions import Annotated, TypedDict

from langchain_cli.utils.find_replace import replace_glob

integration_cli = typer.Typer(no_args_is_help=True, add_completion=False)

Replacements = TypedDict(
    "Replacements",
    {
        "__package_name__": str,
        "__module_name__": str,
        "__ModuleName__": str,
        "__package_name_short__": str,
    },
)

def _process_name(name: str):
    preprocessed = name.replace("_", "-").lower()

    if preprocessed.startswith("langchain-"):
        preprocessed = preprocessed[len("langchain-") :]

    if not re.match(r"^[a-z][a-z0-9-]*$", preprocessed):
        raise ValueError(
            "Name should only contain lowercase letters (a-z), numbers, and hyphens"
            ", and start with a letter."
        )
    if preprocessed.endswith("-"):
        raise ValueError("Name should not end with `-`.")
    if preprocessed.find("--") != -1:
        raise ValueError("Name should not contain consecutive hyphens.")
    return Replacements(
        {
            "__package_name__": f"langchain-{preprocessed}",
            "__module_name__": "langchain_" + preprocessed.replace("-", "_"),
            "__ModuleName__": preprocessed.title().replace("-", ""),
            "__package_name_short__": preprocessed,
        }
    )

@integration_cli.command()
def new(
    name: Annotated[
        str,
        typer.Option(
            help="The name of the integration to create (e.g. `my-integration`)",
            prompt=True,
        ),
    ],
    name_class: Annotated[
        Optional[str],
        typer.Option(
            help="The name of the integration in PascalCase. e.g. `MyIntegration`."
            " This is used to name classes like `MyIntegrationVectorStore`"
        ),
    ] = None,
):
    """
    Creates a new integration package.

    Should be run from libs/partners
    """
    # confirm that we are in the right directory
    if not Path.cwd().name == "partners" or not Path.cwd().parent.name == "libs":
        typer.echo(
            "This command should be run from the `libs/partners` directory in the "
            "langchain-ai/langchain monorepo. Continuing is NOT recommended."
        )
        typer.confirm("Are you sure you want to continue?", abort=True)

    try:
        replacements = _process_name(name)
    except ValueError as e:
        typer.echo(e)
        raise typer.Exit(code=1)

    if name_class:
        if not re.match(r"^[A-Z][a-zA-Z0-9]*$", name_class):
            typer.echo(
                "Name should only contain letters (a-z, A-Z), numbers, and underscores"
                ", and start with a capital letter."
            )
            raise typer.Exit(code=1)
        replacements["__ModuleName__"] = name_class
    else:
        replacements["__ModuleName__"] = typer.prompt(
            "Name of integration in PascalCase", default=replacements["__ModuleName__"]
        )

    destination_dir = Path.cwd() / replacements["__package_name_short__"]
    if destination_dir.exists():
        typer.echo(f"Folder {destination_dir} exists.")
        raise typer.Exit(code=1)

    # copy over template from ../integration_template
    project_template_dir = Path(__file__).parents[1] / "integration_template"
    shutil.copytree(project_template_dir, destination_dir, dirs_exist_ok=False)

    # folder movement
    package_dir = destination_dir / replacements["__module_name__"]
    shutil.move(destination_dir / "integration_template", package_dir)

    # replacements in files
    replace_glob(destination_dir, "**/*", replacements)

    # poetry install
    subprocess.run(
        ["poetry", "install", "--with", "lint,test,typing,test_integration"],
        cwd=destination_dir,
    )


#!/usr/bin/env python
# coding: utf-8

'''
File: cron.py
Project: sjtuannouncements
File Created: 2019/06/03 15:30
Author: Roger Cui (itabas016@gmail.com)
Last Modified: 2019/06/03 15:31
Copyright 2019
'''

from celery.schedules import crontab
from celery.task import periodic_task

from sjtuannouncements import create_app
from sjtuannouncements.task import *
from sjtuannouncements.task import task

app = create_app('env', False)
celery = create_celery(app)

@periodic_task(run_every=(crontab(minute=0, hours='*/6,8-20')), name="scheduled_refresh_announcements_task", ignore_result=True)
def scheduled_refresh_announcements_task():
    with app.app_context():
        task.refresh_announcements()

@celery.task(bind=True)
def refresh_announcements_task(self):
    def listener(current, total, result):
        self.update_state(state='PROGRESS', meta={'progress': current / total})

    with app.app_context():
        return {'progress': 1, 'result': task.refresh_announcements(listener)}


# User APIs.
from typing import List

from flask_login import current_user

from flaskapp import app_logger
from flaskapp.api import users
from flaskapp.http_util import response as response
from flaskapp.http_util.decorators import secure, post, query
from flaskapp.http_util.exceptions import UserNotFound, PermissionDenied
from flaskapp.models import UserModel, Role, RoleModel, RightModel, RolesRightsModel, Right
from flaskapp.structures.structures import Search, SearchResult

def __is_username_taken(username: str) -> bool:
    user = UserModel.find_by_username(username)
    if user:
        return True
    return False

@users.route("/<string:user_id>", methods=["GET"])
@secure(Role.USER)
def get_user(user_id: str):
    user: UserModel = UserModel.find_by_id(user_id)
    if user:
        return response.model_to_response(user)

    return response.empty_response()

@users.route("/roles", methods=["GET"])
@secure(Role.USER)
def get_roles():
    roles: List[RoleModel] = RoleModel.get_all(order_by=RoleModel.label)
    if roles:
        return response.model_to_response(roles)

    return response.empty_response()

@users.route("/rights", methods=["GET"])
@secure(Role.USER)
def get_rights():
    rights: List[RightModel] = RightModel.get_all(order_by=RightModel.right_id)
    if rights:
        return response.model_to_response(rights)

    return response.empty_response()

@users.route("/roleRights/<string:role_id>", methods=["GET"])
@secure(Role.USER)
def get_rights_from_roles(role_id: str):
    right_ids: List[str] = RolesRightsModel.get_rights_by_role(role_id)
    if right_ids:
        return response.string_to_response(right_ids)

    return response.string_to_response([])

@users.route("/all", methods=["GET"])
@secure(Right.VIEW_USER)
def get_users():

    all_users: List[UserModel] = UserModel.get_all()

    if all_users:
        return response.model_to_response(all_users)

    return response.empty_response()

@users.route("/search", methods=["GET"])
@secure(Right.VIEW_USER)
@query(Search)
def search(user_search: Search):

    search_result: SearchResult = UserModel.search(user_search)
    return response.model_to_response(search_result)

@users.route("/username/<string:username>", methods=["GET"])
@secure(Role.USER)
def get_user_by_username(username: str):
    user = UserModel.find_by_username(username)

    if user:
        return response.model_to_response(user)

    return response.empty_response()

@users.route("/isTaken/<string:username>", methods=["GET"])
def is_taken(username: str):
    user_exist = __is_username_taken(username)
    return response.bool_to_response(user_exist)

@users.route("/create", methods=["POST"])
@secure(Right.CREATE_USER)
@post()
def create_user(user: dict):
    # create a user model from user data.
    user_model = UserModel.create_user(user, current_user.id)

    # Check if user with the same username don't exist.
    if __is_username_taken(user_model.username):
        return response.bool_to_response(False)

    created = user_model.save()

    return response.bool_to_response(created)

@users.route("/update", methods=["POST"])
@secure(Right.EDIT_USER)
@post()
def update_user(user: dict):
    # update user
    updated_user = UserModel.update_user(user, current_user.id)

    if not updated_user:
        raise UserNotFound("The user doesn't exist.")

    # return response.bool_to_response(True)
    return response.bool_to_response(updated_user.save())

@users.route("/userSelfUpdate", methods=["POST"])
@secure(Role.USER)
@post()
def user_self_update(user: dict):
    # update user
    updated_user = UserModel.update_user(user, current_user.id, is_self_update=True)

    if not updated_user:
        raise PermissionDenied("Either, this user don't exists or you are trying to update someone that is not you.")

    if updated_user.save():
        return response.model_to_response(updated_user)

    return response.empty_response()

@users.route("/delete/<string:user_id>", methods=["DELETE"])
@secure(Right.DELETE_USER)
def delete_user(user_id):
    user: UserModel = UserModel.find_by_id(user_id)
    if not user:
        raise UserNotFound("The user id {} doesn't exist".format(user_id))

    deleted = user.delete()
    if deleted:
        app_logger.info("User {} has been deleted".format(user.username))
    else:
        app_logger.warning("User {} could't be deleted.".format(user.username))

    return response.bool_to_response(deleted)


#!/usr/bin/env python3

import os
import tempfile
import shutil
import random
import glob
from sklearn.model_selection import train_test_split
from pathlib import Path

num_files_copied = 0
total_num_files = 0

def copy_to_train_val_or_test_dir(src, train_val_or_test):
    global num_files_copied

    dst = f.replace('/all/', f"/{train_val_or_test}/")
    if not os.path.exists(dst):
        os.makedirs(os.path.dirname(dst), exist_ok=True)
        os.link(src, dst)

    num_files_copied += 1
    if num_files_copied % 1000 == 0 or num_files_copied == total_num_files:
        print(f"... Copied {num_files_copied}/{total_num_files}")

if __name__ == '__main__':
    image_files = glob.glob('images/all/**/*.jpg', recursive=True)
    label_files = [f.replace('images/', 'labels/').replace('.jpg', '.txt') for f in image_files]
    train_images, val_images, train_labels, val_labels = train_test_split(
        image_files, label_files, test_size=0.2, random_state=1
    )
    val_images, test_images, val_labels, test_labels = train_test_split(
        val_images, val_labels, test_size=0.5, random_state=1
    )

    total_num_files = (
        len(train_images) + len(train_labels) + len(val_images) + len(val_labels) +
        len(test_images) + len(test_labels)
    )

    for f in train_images + train_labels:
        copy_to_train_val_or_test_dir(f, 'train')
    for f in val_images + val_labels:
        copy_to_train_val_or_test_dir(f, 'val')
    for f in test_images + test_labels:
        copy_to_train_val_or_test_dir(f, 'test')
    print('Done.')


import pytest

class TestLoggerClass:
    def test_LoggerClass_init(self):
        """Test that the module imports and can be created"""
        try:
            from utils import LoggerClass
            logger = LoggerClass()
        except Exception:
            assert False

    def test_gettingRootLogger(self):
        """Tests that we get a valid Logger object"""
        import logging

        from utils import LoggerClass
        assert isinstance(LoggerClass.getRootLogger(), logging.Logger)

    def test_gettingSubLogger(self):
        """Tests that we get a valid Logger object"""
        import logging

        from utils import LoggerClass
        assert isinstance(LoggerClass.getSubLogger("test"), logging.Logger)

    def test_gettingLoggingLevelStrings(self):
        """Test that we get a proper list with the right values"""
        from utils import LoggerClass
        assert list(LoggerClass.getLoggingLevelStrings()) == [
            'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']

class TestLogWindowSignaler:
    def test_LogWindowSignaler(self):
        """Test if the Signal properly emits the string"""
        from utils.Logger import LogWindowSignaler

        def slot(s):
            assert s == "test"

        signaller = LogWindowSignaler()
        signaller.newLogEntry.connect(slot)
        signaller.newLogEntry.emit("test")

class TestSignalLogHandler:
    def test_signal_log_handler(self):
        import logging
        from datetime import datetime
        from logging import LogRecord

        from utils.Logger import SignalLogHandler

        # Create a logger
        logger = logging.getLogger('test_logger')

        # Create a SignalLogHandler and add it to the logger
        handler = SignalLogHandler()
        logger.addHandler(handler)

        # Test that the handler can be attached to a logger and properly
        # emits the newLogEntry signal
        def slot(log_entry):
            print(log_entry)
            assert log_entry.endswith("] [DEBUG   ] "
                                      "test_logger: test message")
        handler.signal.newLogEntry.connect(slot)

        # Log a message
        logger.debug("test message")

        # Test that the format of the emitted string matches
        # the specified formatter
        record = LogRecord('test_logger', logging.DEBUG, '', 0,
                           'test message', args=(), exc_info=None)
        assert handler.format(record).endswith(
            "] [DEBUG   ] test_logger                   : test message")

        # Test that the level can be changed with the changeLevel
        # function and that change is properly reflected in
        # the object's state
        handler.changeLevel('INFO')
        assert handler.level == logging.INFO


# -*- coding: utf-8 -*-
from common.db_sum import _metric_meta_db
from common.sql_tools import Where

class OperBase:
    @staticmethod
    def get_data_by_ids(ids=()):
        """ 暂时只支持根据ID搜索 或者多选 """
        where = Where("id").in_(ids)
        if where:
            where = " WHERE {}".format(where)
        return _metric_meta_db.query("SELECT * FROM `t_chart_fields_oper` {};".format(where))

    @staticmethod
    def by_ds_type(type, ds_types):
        return _metric_meta_db.query("SELECT * FROM `t_chart_fields_oper` WHERE `ds_types` = '{}' AND"
                                     " `fields_types` = '{}';".format(ds_types, type))


"""
https://leetcode.com/problems/count-all-possible-routes/
"""

from functools import lru_cache

class Solution:
    def countRoutes(
        self,
        locations: list[int],
        start: int,
        finish: int,
        fuel: int
    ) -> int:
        @lru_cache(None)
        def dfs(currCity: int, remainFuel: int) -> int:
            if remainFuel < 0:
                return 0

            cnt = 0
            if currCity == finish:
                cnt += 1

            for nextCity in range(len(locations)):
                if nextCity != currCity:
                    cnt += dfs(
                        nextCity,
                        remainFuel -
                        abs(locations[nextCity] - locations[currCity])
                    )

            return cnt

        return dfs(start, fuel) % (10 ** 9 + 7)


import os
import csv
import ctypes
import random
from faker import Faker

FORMAT = 'utf-8'

class UserData(ctypes.Structure):
    _fields_ = [("user_name", ctypes.c_char_p),
                ("user_credit_score", ctypes.c_short),
                ("user_monthly_income", ctypes.c_double),
                ("user_financial_reserves", ctypes.c_double),
                ("user_debt_to_income_ratio", ctypes.c_double),
                ("user_loan_amoumnt_requested", ctypes.c_double),
                ("user_loan_duration", ctypes.c_int)]

def generate_data (num_data_to_generate):

    fake = Faker()

    loan_data_header = ['Name', "credit score", 'monthly income', 'financial reserves', 'debt to income ratio', 'Duration in months', 'loan amount requested']
    loan_data = []

    min_options = 0
    max_options = 10000

    if ((num_data_to_generate < min_options) or (num_data_to_generate > max_options)):
        print(" Data entered is in invalid format. \n")

    else:
        num_data_to_generate = int(num_data_to_generate)

        # Generate user data
        for i in range(num_data_to_generate):
            credit_score = random.randint(300, 850)
            user_name = fake.name()
            user_monthly_income = round(random.uniform(900, 12000), 2)
            user_debt_to_income_ratio = round(random.uniform(0.00, 1.00), 2)

            if (user_monthly_income < 3000):
                financial_reserves = round(random.uniform(500.00, 5000.00), 2)
            elif (user_monthly_income > 3000 and user_monthly_income < 5000):
                financial_reserves = round(random.uniform(5000.00, 10000.00), 2)
            elif (user_monthly_income > 5000 and user_monthly_income < 10000):
                financial_reserves = round(random.uniform(10000.00, 20000.00), 2)
            elif (user_monthly_income > 10000 and user_monthly_income <= 20000):
                financial_reserves = round(random.uniform(20000.00, 35000.00), 2)
            else:
                financial_reserves = round(random.uniform(35000.00, 50000.00), 2)

            loan_duration_in_months = random.randint(2, 60)
            loan_amonut_requested = random.randint(500, 20000)

            loan_data.append([user_name, credit_score, user_monthly_income, financial_reserves, user_debt_to_income_ratio, loan_duration_in_months, loan_amonut_requested])

        if os.path.exists("allGeneratedLoanData.csv"):
            with open("allGeneratedLoanData.csv", "a", newline = '') as file:
                writer = csv.writer(file)
                writer.writerows(loan_data)
        else:
            with open("allGeneratedLoanData.csv", "w", newline = '') as file:
                writer = csv.writer(file)
                writer.writerow(loan_data_header)
                writer.writerows(loan_data)

        with open("tempGeneratedLoanDataForDbStorage.csv", "w", newline = '') as file:  # This is used to store newly generated data to be used
            writer = csv.writer(file)
            writer.writerow(loan_data_header)
            writer.writerows(loan_data)

        print(" Loan data has been written successfully.")

def test_changing_base_rate(cpp_library):
    this_months_prime_rate_from_cpp = cpp_library.getThisMonthsPrimeRate
    this_months_prime_rate_from_cpp.restype = ctypes.c_double
    this_months_spread_from_cpp = cpp_library.getSpread
    this_months_spread_from_cpp.restype = ctypes.c_double

    this_months_federal_funds_rate_double = ctypes.c_double(6.00)
    this_months_federal_funds_rate = 6.00

    cpp_library.changeBaseRate(this_months_federal_funds_rate_double)

    if(this_months_prime_rate_from_cpp() == ((this_months_federal_funds_rate) + this_months_spread_from_cpp())):
        print(f" This months prime rate set successfully. This is its value: {this_months_spread_from_cpp()}")
    else:
        # test = cpp_library.getThisMonthsPrimeRate
        # test.restype = ctypes.c_double

        print(f" Not accurate, failed test. This months prime rate is: {this_months_prime_rate_from_cpp()}")
        print(f" This is this months spread {cpp_library.getSpread()}")

def test_adding_and_computing_for_single_user_data(customer_data, cpp_library):
    user_data = customer_data

    user_name = user_data['user_name'].encode(FORMAT)

    data_to_cpp = UserData(user_name, int(user_data['user_credit_score']), float(user_data['user_monthly_income']), float(user_data['user_financial_reserves']), float(user_data['user_debt_to_income_ratio']), float(user_data['user_loan_amoumnt_requested']), int(user_data['user_loan_duration']))

    added_data_sucessfully = cpp_library.addIndividualizedDataToDb(data_to_cpp)

def test_storing_all_db_values_in_csv_for_analysis(cpp_library):
    pass

def test_storing_generated_data_in_db_from_csv(cpp_library):
    print(" Test stroing generated data")
    required_dev_menu_response = 3

    generate_data(100)

    error_storing_generated_data = bool(cpp_library.readAndStoreGeneratedDataInDb(required_dev_menu_response))

    return error_storing_generated_data

def test_coputing_loan_related_values_from_generated_data_without_storing_data():
    pass


import xml.etree.ElementTree as ET
import numpy
import os
import json
import sys

output_json = sys.argv[1]
input_files = sys.argv[2]

input_files = input_files.split(",")
input_files =  [os.path.abspath(input_file) for input_file in input_files]
output_json = os.path.abspath(output_json)

# Function to return dictionary of dict[parent] = [child1,child2,child3]
# Each parent is a brain region term
def extract_xml(xmlfile,parent_id="canonical",child_id="base"):
    source = os.path.split(xmlfile)[-1].replace(".xml","")
    tree = ET.parse(xmlfile)
    root = tree.getroot()
    nodes = dict()
    # Here we are iterating through tokens
    for child in root:
        parent = child.attrib[parent_id].lower()
        children = []
        # Get any child nodes
        for variant in child:
            children.append({"name":variant.attrib[child_id].lower()})
        nodes[parent] = {"name":parent_id,
                        "variants":children,
                        "ref_id":child.attrib["ref_id"]}
    result = {"nodes":nodes,"source":source}
    return result

# Extract brain region dictionaries
xmls = []
for input_file in input_files:
    xmls.append(extract_xml(input_file))

def merge_dicts(regions,regiondict):
    for name,others in regiondict["nodes"].iteritems():
        if name in regions:
            holder = regions[name]
            for region in others["variants"]:
                if not region["name"] in holder["variants"]:
                    holder["variants"].append(region["name"])
            holder["ref_id"] = holder["ref_id"] + [others["ref_id"]]
            regions[name] = holder
        else:
            variants = []
            for region in others["variants"]:
                variants.append(region["name"])
            regions[name] = {"variants": variants,
                             "ref_id": [others["ref_id"]]}
    return regions

# Combine them into one
regions = dict()
for x in xmls:
    regions = merge_dicts(regions,x)

# Now make it proper json!
result = []
for region,info in regions.iteritems():
    result.append({"name":region,
                   "ref_id":info["ref_id"],
                   "variants":numpy.unique(info["variants"]).tolist()})

# Write to output file
filey = open(output_json,'wb')
filey.write(json.dumps(result, sort_keys=True,indent=4, separators=(',', ': ')))
filey.close()