import csv
import json
from symbol import except_clause
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By

import time

browser = webdriver.Chrome(ChromeDriverManager().install())
links = ['https://www.zomato.com/ncr/delivery-in-south-delhi', 'https://www.zomato.com/ncr/delivery-in-north-delhi',
         'https://www.zomato.com/ncr/delivery-in-east-delhi', 'https://www.zomato.com/ncr/delivery-in-west-delhi', 'https://www.zomato.com/ncr/delivery-in-central-delhi']
restaurants = {}
for link in links:
    browser.get(link)
    time.sleep(2)
    restaurants[link] = set()

    rows = browser.find_elements(By.CSS_SELECTOR, ".sc-doWzTn")
    while len(rows) < 17:
        browser.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)
        rows = browser.find_elements(By.CSS_SELECTOR, ".sc-1mo3ldo-0")
        print(len(rows))

    # find all links hrefs

    a_links = browser.find_elements_by_tag_name('a')
    # for a in a_links:

    print(len(a_links))
    # filter links having /order in them
    iteration = 0
    for a in a_links:
        print(iteration)
        href = a.get_attribute('href')
        try:
            if 'order' in href:
                restaurants[link].add(href)
        except:
            pass
        iteration += 1
    restaurants[link] = list(restaurants[link])
    # for row in rows:
    #     # print all elements in row
    #     try:
    #         # print(row.find_elements_by_tag_name("a"))
    #         restaurants[link].add(row.find_element_by_tag_name("a").get_attribute("href"))
    #     except:
    #         print("Error")
    #         pass
        # try:
        #     jumbo_tracker = row.find_element(By.CSS_SELECTOR, ".jumbo-tracker")
        #     if jumbo_tracker:
        #         a_link = jumbo_tracker.find_element(By.HTML, "a")
        #         restaurants[link].append(a_link.get_attribute("href"))
        #     else:
        #         print("No jumbo tracker")
        # except:
        #     print("No jumbo tracker")
        #     pass
    # break

print(restaurants)
print(len(restaurants))
# add to json file named zomato.json
with open('zomato.json', 'w') as f:
    json.dump(json.dumps(restaurants), f)

# - Created a web scraper using python and selenium to scrape data from zomato website.
# - The script is able to go to five different locations and scrape the data from the page.
# - Challenges:
#     - The page is dynamic and the data is loaded using lazy loading. We have to scroll down to load more data.
#     - The data is loaded in a grid format and we have to extract the data from each grid.
#     - The scraper needs to visit multiple pages and extract data from each page. This requires a lot of time

with open('zomato.json') as f:
    data = json.load(f)
    print(data)

browser = webdriver.Chrome(ChromeDriverManager().install())
restaurants = {}
for link in data:
    restaurants[link] = []
    for href in data[link]:
    # href = data[link][0]
        browser.get(href)
        time.sleep(2)
        try:
            name = browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/main/div/section[3]/section/section/div/div/div/h1').text
        except:
            name = ""
        try:
            rating = browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/main/div/section[3]/section/section/div/div/div/section/div[3]/div[1]/div/div/div[1]').text
        except:
            rating = "0"
        browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/main/div/article/div/section/section/div[1]/h2/a').click()
        time.sleep(2)
        try:
            address = browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/article/section/p').text
        except:
            address = ""
        try:
            phone = browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/article/p').text.split('#')[0]
        except:
            phone = ""
        try:
            popularDishes = browser.find_element(by = By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/section/article[1]/section[1]/p[1]').text
            popularDishes = popularDishes.split(', ')
        except:
            popularDishes = []
        try:
            knownFor = browser.find_element(by = By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/section/article[1]/section[1]/p[2]').text
            knownFor = knownFor.split(', ')
        except:
            knownFor = []
        try:
            avgCost = browser.find_element(by = By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/section/article[1]/section[1]/p[3]').text.split(' ')[0].split('₹')[1]
        except:
            avgCost = ""
        try:
            cuisineSection = browser.find_element(by = By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/section/article[1]/section[1]/section[3]')
            cuisine = cuisineSection.find_elements(by = By.TAG_NAME, value='a')
            cuisine = [c.text for c in cuisine]
        except:
            cuisine = []
        try:
            reviewSection = browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/main/div/section[4]/section/section/section[2]/div')
            reviewHighlights = reviewSection.find_elements(by=By.TAG_NAME, value='span')
            reviewHighlights = [r.text for r in reviewHighlights]
            if 'Write a Review' in reviewHighlights:
                reviewHighlights.remove('Write a Review')
        except:
            reviewHighlights = []
        print(name, rating, address, phone, popularDishes, knownFor, avgCost, cuisine, reviewHighlights)
        # write to json file
        restaurants[link].append({
            'name': name,
            'rating': rating,
            'address': address,
            'phone': phone,
            'popularDishes': popularDishes,
            'knownFor': knownFor,
            'avgCost': avgCost,
            'cuisine': cuisine,
            'reviewHighlights': reviewHighlights
        })
        with open('zomatoData.json', 'w') as f:
            json.dump(restaurants, f)
        # write to zomato.csv
    # with open('zomato.csv', 'a', encoding='utf-8') as f:
    #     writer = csv.writer(f)
    #     writer.writerow([name, rating, address, phone, popularDishes, knownFor, avgCost, cuisine, reviewHighlights])


from signal import pthread_sigmask
import sys
input = sys.stdin.readline
n, s = map(int, input().split())
arr = list(map(int, input().split()))
p_sum = [0] * (n+1)
for i in range(n):
    p_sum[i+1] = p_sum[i]+arr[i]
l, ans = 0, sys.maxsize
for i in range(n+1):
    while(p_sum[i]-p_sum[l]) >= s:
        if p_sum[i]-p_sum[l+1] < s:
            break
        l+=1
    if p_sum[i]-p_sum[l] >= s:
        ans = min(ans, i-l)
        if ans == 1: break
print(ans) if ans != sys.maxsize else print(0)


from pygame import display

from character import Character

class Enemy(Character):
    def __init__(self, screen, name, hp, mp, attack, spells, img, coordinate):
        super().__init__(name, hp, mp, attack, spells)
        self.screen = screen
        self.coordinate = coordinate
        self.img = img

    def draw(self):
        self.screen.blit(self.img, self.coordinate)
        display.flip()


def main():
    try:
        filein = open("shuffle.in", "r")
        file = open("shuffle.out", "w")
        print("files opened")
        n = int(filein.readline())
        #n=10

        # array with shuffle from input
        shuffle = filein.readline().split(' ')
        shuffle = [int(i)-1 for i in shuffle]
        #shuffle = [0,1,0,3,2,4,9,8,2,6]
        print("shuffle: ", shuffle)

        # array with the number of times a cow is pointed to each position
        pointers = [0] * n
        print("pointers: ", pointers)

        # queue with all dead positions
        from queue import Queue
        q = Queue(maxsize = n)
        # number of positions processed through queue
        dead = 0
        print("queue: ", q, " dead: ", dead)
        print("queuesize: ", q.qsize())

        # loop through all numbers in array and fill pointers
        for i in range(0,n):
            pointers[shuffle[i]] += 1
        print("pointers: ", pointers)

        # add all positions with value 0 in pointers to queue
        for i in range(0,n):
            if(pointers[i] == 0):
                print("pos: ", i, " has a value of 0")
                q.put(i)
        print("filled queue: ", q)
        print("queuesize: ", q.qsize())

        # process queue until empty
        while(q.empty() == False):
            print("dead: ", dead, " current queue: ", q)
            dead += 1
            pos = q.get()
            dest = shuffle[pos]
            pointers[dest] -= 1
            if(pointers[dest] == 0):
                q.put(dest)
        print("final pointers: ", pointers)

        # output total number of locations - locations processed through queue
        #file.write("test")
        file.write(str(n-dead))
        file.close()
    except:
        print("exception")
if __name__=="__main__":
    main()


import os

import pytest
import lxml.etree

from aristo.core.knowledge_creator import KnowledgeCreator

test_data = [
    (["sinkhole"], 1, 1),
    (["56fsvhvnbv"], 2, 0),
    (["sinkhole", "cell"], 1, 2),
    (["sinkhole", "cell"], 5, 2)

]

@pytest.mark.parametrize("articles, batch_size, expected_answer", test_data)
def test_should_download_articles(tmpdir, articles, batch_size, expected_answer):
    output_file = str(tmpdir.mkdir("test_should_predict_the_correct_answer").join("wiki.xml"))
    sut = KnowledgeCreator()
    actual = 0;
    for file in sut.download_corpus(articles, output_file, batch_size):
        doc = lxml.etree.parse(file)
        actual = actual + doc.xpath('count(/*[local-name() = "mediawiki"]/*[local-name() = "page"])')
    assert actual == expected_answer


from typing import Any
from absl.testing import parameterized

import tensorflow as tf
from tensorflow_gnn.models.contrastive_losses.deep_graph_infomax import layers

class DeepGraphInfomaxLogitsTest(tf.test.TestCase, parameterized.TestCase):

  @parameterized.named_parameters([
      dict(
          testcase_name="NonSequenceInput",
          inputs=tf.constant(range(8)),
          expected_error=r"Expected `Sequence` \(got .*\)",
      ),
      dict(
          testcase_name="InvalidSequenceInput",
          inputs=[tf.constant(range(8))] * 4,
          expected_error=r"Expected `Sequence` of length 2 \(got .*\)",
      ),
      dict(
          testcase_name="IncompatabileShapeInput",
          inputs=[tf.constant(range(8)), tf.constant(range(4))],
          expected_error=r"Shapes \(8,\) and \(4,\) are incompatible",
      ),
      dict(
          testcase_name="UndefinedInnerDimension",
          inputs=[tf.keras.Input((2, None)), tf.keras.Input((2, None))],
          expected_error=r"Expected a defined inner dimension \(got .*\)",
      ),
  ])
  def test_value_error(
      self,
      inputs: Any,
      expected_error: str):
    """Verifies invalid input raises `ValueError`."""
    with self.assertRaisesRegex(ValueError, expected_error):
      _ = layers.DeepGraphInfomaxLogits()(inputs)

  def test_deep_graph_infomax(self):
    """Verifies output logits shape."""
    x_clean = tf.random.uniform((1, 4))
    x_corrupted = tf.random.uniform((1, 4))
    logits = layers.DeepGraphInfomaxLogits()((x_clean, x_corrupted))

    # Clean and corrupted logits (i.e., shape (1, 2)).
    self.assertEqual(logits.shape, (1, 2))

if __name__ == "__main__":
  tf.test.main()


# 11. 盛最多水的容器

"""
给你 n 个非负整数 a1，a2，...，an，每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线，垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线，使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明：你不能倾斜容器，且 n 的值至少为 2。

 垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下，容器能够容纳水（表示为蓝色部分）的最大值为 49。

示例：

输入：[1,8,6,2,5,4,8,3,7]
输出：49
"""
import json

class Solution:
    def maxArea(self, height: list) -> int:
        if not height:
            return 0
        left, right = 0, len(height) - 1
        res = 0
        while left < right:
            res = max(res, (right-left) * min(height[left], height[right]))
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return res

def stringToIntegerList(input):
    return json.loads(input)

def main():
    import sys
    import io
    def readlines():
        for line in io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8'):
            yield line.strip('\n')

    lines = readlines()
    while True:
        try:
            line = next(lines)
            height = stringToIntegerList(line);

            ret = Solution().maxArea(height)

            out = str(ret);
            print(out)
        except StopIteration:
            break

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-
"""
Created on Sun Jan 30 22:43:26 2022

@author: dvnny

DESCRIPTION

Practicing web scraping with BeautifulSoup4

Trying to pull coaching information from

"""

from bs4 import BeautifulSoup
import requests
import pandas as pd

# https://www.pro-football-reference.com/teams/nyj/coaches.htm#coaches_year

pfr_teams_site = "https://www.pro-football-reference.com/teams/"
suffix = "/coaches.htm#coaches_year"

team = "nyj"

r = requests.get(pfr_teams_site + team + suffix)

# Previewing info about the response
# print(r.headers)
# print(r.text)

soup = BeautifulSoup(r.text, "html.parser")
# print(soup.table)

# tables = soup.find_all('div', {'table'})
tables = soup.find_all('table')

# print(soup.prettify())

coach_data = tables[1]
print(coach_data)

df = pd.read_html(str(coach_data))[0]

print(df.head())
print(df.info())
print(df.columns)

df.columns = ["year","coach","regular_season_games","wins","losses","ties","win_percentage","playoff_games","playoff_wins","playoff_losses",\
                                  "playoff_result","coordinator_offense","coordinator_defense"]

#df.rename(columns={'Year':"year",'Coach':"coach",'G':"regular_season_games",'W':"win",'L':"loss",'T':"tie",'W-L%':"win_percentage"}, inplace=True)
                   # ,"playoff_games","playoff_win","playoff_loss","playoff_result","coordinator_offense","coordinator_defense"})
# df.astype({"year":"int64"}).dtypes

print(df.info())


from openerp.osv import fields, orm
from openerp.tools.translate import _
import openerp.addons.decimal_precision as dp

class account_invoice(orm.Model):
    _inherit = "account.invoice"

    _columns = {
        'sale_order_ids': fields.many2many('sale.order', 'sale_order_invoice_rel',
                                           'invoice_id', 'order_id', 'Sale Order',
                                           readonly=True),
    }

    def _check_if_ecotax(self, cr, uid, line, context=None):
        if context is None:
            context = {}
        if not line.product_id or \
            (not line.product_id.ecotax_type in ['1','2'] and \
             not line.product_id.categ_id.ecotax_type in ['1','2'])and \
             not line.invoice_id.partner_id.country_id.subject_to_ecotax is True:
            return False
        return True

    def generate_ecotax_line(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        line_obj = self.pool.get('account.invoice.line')
        for invoice in self.browse(cr, uid, ids, context=context):
            product_list = {}
            if invoice.state != 'draft':
                continue
            for line in invoice.invoice_line:
                if not self._check_if_ecotax(cr, uid, line, context=context):
                    continue
                if line.product_id.ecotax_product_id and \
                    line.product_id.ecotax_product_id.id not in product_list.keys():
                    product_list.update({line.product_id.ecotax_product_id.id: line.quantity})
                elif line.product_id.ecotax_product_id:
                    product_list[line.product_id.ecotax_product_id.id] += line.quantity
                elif line.product_id.categ_id.ecotax_product_id and \
                    line.product_id.categ_id.ecotax_product_id.id not in product_list.keys():
                    product_list.update({line.product_id.categ_id.ecotax_product_id.id: line.quantity})
                elif line.product_id.categ_id.ecotax_product_id:
                    product_list[line.product_id.categ_id.ecotax_product_id.id] += line.quantity
            line_obj._genrate_ecotax_lines(cr, uid, invoice, product_list, context=context)
        return True

    def _amount_ecotax(self, cr, uid, ids, field_name, arg, context=None):
        cur_obj = self.pool.get('res.currency')
        res = {}
        for invoice in self.browse(cr, uid, ids, context=context):
            res[invoice.id] = {
                'amount_ecotax': 0.0,
            }
            val = 0.0
            cur = invoice.currency_id
            for line in invoice.invoice_line:
                if line.ecotax:
                    val += line.price_subtotal
            res[invoice.id]['amount_ecotax'] = cur_obj.round(cr, uid, cur, val)
        return res

    def _get_invoices(self, cr, uid, ids, context=None):
        result = {}
        for line in self.pool.get('account.invoice.line').browse(
                                        cr, uid, ids, context=context):
            result[line.invoice_id.id] = True
        return result.keys()

    _columns = {
        'amount_ecotax': fields.function(_amount_ecotax,
            digits_compute=dp.get_precision('Account'),
            string='Included ecotax', store={
                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 10),
                'account.invoice.line': (_get_invoices,
                     ['price_unit', 'invoice_line_tax_id', 'discount', 'quantity', 'ecotax'],
                     20),
            },
            multi='sums', help="The included ecotax amount."),
    }

class account_invoice_line(orm.Model):
    _inherit = "account.invoice.line"

    _columns = {
        'ecotax': fields.boolean('Ecotax line'),
    }

    _defaults = {
        'ecotax': False,
        'sequence': 1,
    }

    def _genrate_ecotax_lines(self, cr, uid, invoice,
                              product_list, context=None):
        if context is None:
            context = {}
        line_to_del_ids = self.search(cr, uid, [
                ('invoice_id', '=', invoice.id),
                ('ecotax', '=', True),
                ('invoice_id.state', '=', 'draft'),
            ], context=context)
        self.unlink(cr, uid, line_to_del_ids, context=context)
        for product_id in product_list.keys():
            res = self.product_id_change(cr, uid, [], product=product_id,
                uom_id=False, qty=product_list[product_id], name='',
                type='out_invoice', partner_id=invoice.partner_id.id,
                fposition_id=invoice.fiscal_position.id,
                price_unit=False, currency_id=invoice.currency_id.id,
                context=context)
            vals = res.get('value')
            if vals:
                invoice_line_tax_id = vals.get('invoice_line_tax_id', [])
                vals.update({
                    'ecotax': True,
                    'invoice_id': invoice.id,
                    'product_id': product_id,
                    'quantity': product_list[product_id],
                    'sequence': 1000,
                    'invoice_line_tax_id': [(6, 0, invoice_line_tax_id)]
                })
                self.create(cr, uid, vals, context=context)
        return True

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:


from TreeNode import TreeNode

class SmalestSubtreeWithAllDeepestNodes:
    # def subtreeWithAllDeepest(self, root: TreeNode) -> TreeNode:
    #     def deep(node):
    #         if not node:
    #             return 0, None
    #         ld = deep(node.left)
    #         rd = deep(node.right)
    #
    #         if ld[0] > rd[0]:
    #             return ld[0] + 1, ld[1]
    #         elif rd[0] > ld[0]:
    #             return rd[0] + 1, rd[1]
    #         else:
    #             return ld[0] + 1, node
    #     return deep(root)[1]

    def subtreeWithAllDeepest(self, root: TreeNode) -> TreeNode:
        return self.getDeepTree(root)[1]

    def getDeepTree(self, node):
        if not node:
            return (0, None)

        left = self.getDeepTree(node.left)
        right = self.getDeepTree(node.right)

        if left[0] > right[0]:
            return (left[0] + 1, left[1])
        elif right[0] > left[0]:
            return (right[0] + 1, right[1])
        else:
            return (left[0] + 1, node)

if __name__ == '__main__':
    init = SmalestSubtreeWithAllDeepestNodes()
    root = TreeNode(3)
    root.left = TreeNode(5)
    root.left.left = TreeNode(6)
    root.left.right = TreeNode(2)
    root.left.right.left = TreeNode(7)
    root.left.right.right = TreeNode(4)
    root.right = TreeNode(1)
    root.right.left = TreeNode(0)
    root.right.right = TreeNode(8)
    print(init.subtreeWithAllDeepest(root))


import unittest

from websockets.sync.utils import *

from ..utils import MS

class DeadlineTests(unittest.TestCase):
    def test_timeout_pending(self):
        """timeout returns remaining time if deadline is in the future."""
        deadline = Deadline(MS)
        timeout = deadline.timeout()
        self.assertGreater(timeout, 0)
        self.assertLess(timeout, MS)

    def test_timeout_elapsed_exception(self):
        """timeout raises TimeoutError if deadline is in the past."""
        deadline = Deadline(-MS)
        with self.assertRaises(TimeoutError):
            deadline.timeout()

    def test_timeout_elapsed_no_exception(self):
        """timeout doesn't raise TimeoutError when raise_if_elapsed is disabled."""
        deadline = Deadline(-MS)
        timeout = deadline.timeout(raise_if_elapsed=False)
        self.assertGreater(timeout, -2 * MS)
        self.assertLess(timeout, -MS)

    def test_no_timeout(self):
        """timeout returns None when no deadline is set."""
        deadline = Deadline(None)
        timeout = deadline.timeout()
        self.assertIsNone(timeout, None)


#!/usr/local/bin/python3
# Use C-c C-j to search
# AnnotationTester is the class - first function test_good_values

import unittest
import argparse
from collections import OrderedDict
from collections import namedtuple

from annotate_test import annotate_test

# Global variable area for constants
# debug_except = input("Debug exceptions? y/n : ")
# debug_except = str(debug_except)[0]

def debug(self, func, args, kwargs):
    with self.assertRaises(ValueError):
        try:
            func(*args, **kwargs)
        except ValueError as e:
            print("##DEBUG EXCEPTION in {} ##".format(func.__name__))
            print("Values: ", args, kwargs)
            print("ValueError returned msg")
            print(e)
            print('')
            raise

def assert_pass(self, cases):
    for answer, func, args, kwargs in cases:
        self.assertEqual(answer, func(*args, **kwargs))

def assert_fail(self, cases):
    for answer, func, args, kwargs in cases:
        if debug_except.upper() == "Y":
            debug(self, func, args, kwargs)
        self.assertRaises(ValueError, func, *args, **kwargs)

# Global variable area (for functions and classes):

class BlankClass(object):
    """This is a BlankClass to test.  It will allow an instance."""

    def __init__(self, a, b):
        self.a = a
        self.b = b

    @staticmethod
    def functiontest(a, b):
        return a + b

def basicfunc(a, b):
    return a + b

def twofuncy(c, d):
    return c + d
# Area for functions to test

# Area for namedtuple
tupname = namedtuple('tupname', ('one', 'two', 'three'))
dif_namedtuple = namedtuple('different', ('one', 'two', 'three'))

# Odd semantic testing (Complete)

@annotate_test
def missing_annotation(a, b: 'str', c: 'int'):
    return (a, b + str(c))

# bool only has type (Complete)

@annotate_test
def f_bool(a: 'bool', b: 'bool') -> 'bool':
    return a ^ b  # Return xor of a and b

@annotate_test
def f_broken_bool(a: 'bool', b: 'bool') -> 'str':
    return a ^ b

# str only has type (Complete)

@annotate_test
def f_str(a: 'str', b: 'str'='default') -> 'str':
    return a + b

# int only has type (Complete)

@annotate_test
def f_int(a: 'int', b: 'int') -> 'int':
    return a + b

# float only has type (Complete)

@annotate_test
def f_float(a: 'float', b: 'float') -> 'float':
    return a + b

# complex only has type (Complete)

@annotate_test
def f_complex(a: 'complex', b: 'complex') -> 'complex':
    return a + b

# bytes only has type (Complete)

@annotate_test
def f_bytes(a: 'bytes', b: 'bytes') -> 'bytes':
    return a + b

# bytearray only has type (Complete)

@annotate_test
def f_bytearray(a: 'bytearray', b: 'bytearray') -> 'bytearray':
    return a + b

# Class has match to a class type (Complete)

@annotate_test
def f_Class(a: 'Class BlankClass',
            b: 'Class BlankClass'
            )->'tuple[Class BlankClass, Class BlankClass]':
    return a, b

# ClassInst has match against a class

@annotate_test
def f_ClassInst(a: 'ClassInst BlankClass',
                b: 'ClassInst BlankClass'
                ) -> 'tuple[ClassInst BlankClass]':
    return a, b

# Func testing method has type and match (Completed)

@annotate_test
def f_Func_type(a: 'Func') -> 'Func':
    return a

@annotate_test
def f_Func_static(
        a: 'Func BlankClass.functiontest',
        b: 'Func BlankClass.functiontest'
) -> 'tuple[Func BlankClass.functiontest, Func BlankClass.functiontest]':
    return a, b

@annotate_test
def f_Func_match(a: 'Func basicfunc') -> 'Func basicfunc':
    return a

# tuple has type, single, positional and group (Completed)

@annotate_test
def f_tuple_t(a: 'tuple') -> 'tuple':
    return a

@annotate_test
def f_tuple_s(a: 'tuple[int]') -> 'tuple[int]':
    return a

@annotate_test
def f_tuple_p(a: 'tuple[int, str]') -> 'tuple':
    return a

@annotate_test
def f_tuple_g(a: 'tuple[int|str]') -> 'tuple[int|str]':
    return a

# frozenset has type and group (Completed)

@annotate_test
def f_frozenset_t(a: 'frozenset') -> 'frozenset':
    return a

@annotate_test
def f_frozenset_g(a: 'frozenset[int|str]') -> 'frozenset[int|str]':
    return a

# set has type and group (Completed)

@annotate_test
def f_set_t(a: 'set') -> 'set':
    return a

@annotate_test
def f_set_g(a: 'set[int|str]') -> 'set[int|str]':
    return a

# list has type, positional, single and group (Completed)

@annotate_test
def f_list_t(a: 'list') -> 'list':
    return a

@annotate_test
def f_list_p(a: 'list[int, str]') -> 'list':
    return a

@annotate_test
def f_list_g(a: 'list[int|str]') -> 'list':
    return a

# OrderedDict has type, positional, grouped, key only and value only
# (Completed)

@annotate_test
def f_OrderedDict_t(a: 'OrderedDict') -> 'OrderedDict':
    return a

@annotate_test
def f_OrderedDict_p(a: 'OrderedDict[str=int,bytes=str]') -> 'OrderedDict':
    return a

@annotate_test
def f_OrderedDict_g(a: 'OrderedDict[str|bytes=bytes|int') -> 'OrderedDict':
    return a

@annotate_test
def f_OrderedDict_key_only(a: 'OrderedDict[str|bytes]') -> 'OrderedDict':
    return a

@annotate_test
def f_OrderedDict_value_only(a: 'OrderedDict[=int|bytes]') -> 'OrderedDict':
    return a

# dict has type, group, key only and value only
#   (group is done only against values as keys are hashable)
# (Completed)

@annotate_test
def f_dict_t(a: 'dict') -> 'dict':
    return a

@annotate_test
def f_dict_g(a: 'dict[str=int]') -> 'dict':
    return a

@annotate_test
def f_dict_key_only(a: 'dict[str|bytes') -> 'dict':
    return a

@annotate_test
def f_dict_value_only(a: 'dict[=int|bytes') -> 'dict':
    return a

# namedtuple has type, positional and group
# (Completed)

@annotate_test
def f_namedtuple_t(a: 'namedtuple'):
    """This is to match namedtuple type"""
    return a

@annotate_test
def f_namedtuple_n(a: 'namedtuple(tupname)'):
    """This is to match name of tuple"""
    return a

@annotate_test
def f_namedtuple_p(a: 'namedtuple(tupname[int, bytes, str])'):
    return a

@annotate_test
def f_namedtuple_g(a: 'namedtuple(tupname[int|str])'):
    return a

class AnnotationTester(unittest.TestCase):
    """AnnotationTester will test simple and complex annotation
syntax.  Tests will be built from simple to complex cases."""

    # Return testing / broken

    def test_broken_return(self):
        """Return value exceptions"""
        known_exceptions = (
            (True, f_broken_bool, (True, True), dict()),
        )
        assert_fail(self, known_exceptions)

    # Odd semantic testing
    def test_good_missing_annotation(self):
        """This tests for semantic issues around missing annotations"""
        known_good = (
            (('Hello', 'Next5'), missing_annotation,
             ('Hello', 'Next'), dict(c=5)),
            (('Why', 'Now10'), missing_annotation,
             ('Why',), dict(c=10, b='Now'))
        )
        assert_pass(self, known_good)

    def test_except_missing_annotation(self):
        known_exceptions = (
            ('n/a', missing_annotation, (4, 5), dict()),
            ('n/a', missing_annotation, (), dict(a='No', c=40, b=20))
        )
        assert_fail(self, known_exceptions)

    # bool has type only (Complete)

    def test_good_bool(self):
        """Bool known good"""
        known_good = (
            (True, f_bool, (True, False), dict()),
            (False, f_bool, (False,), dict(b=False))
        )
        assert_pass(self, known_good)

    def test_except_bool(self):
        """Bool exceptions"""
        known_exceptions = (
            (True, f_bool, (3, False), dict()),  # With int in args
            (True, f_bool, (True,), dict(b=3)),  # With int in keyword
        )
        assert_fail(self, known_exceptions)

    # str has type only (Complete)
    def test_good_str(self):
        """String known good"""
        known_good = (
            ('yesno', f_str, ('yes', 'no'), dict()),
            ('yesno', f_str, ('yes', ), dict(b='no')),
            ('yesno', f_str, (), dict(a='yes', b='no')),
        )
        assert_pass(self, known_good)

    def test_except_str(self):
        """String exceptions"""
        known_exceptions = (
            ('n/a', f_str, (3, 'no'), dict()),
            ('n/a', f_str, ('no',), dict(b=3)),
            ('n/a', f_str, (), dict(a='no', b=3))
        )
        assert_fail(self, known_exceptions)

    # int has type only (Complete)
    def test_good_int(self):
        """Int known good"""
        known_good = (
            (20, f_int, (7, 13), dict()),
            (20, f_int, (12,), dict(b=8)),
            (20, f_int, (), dict(a=-22, b=42))
        )
        assert_pass(self, known_good)

    def test_except_int(self):
        """Int exceptions"""
        known_exceptions = (
            ('n/a', f_int, ('ten', 10), dict()),
            ('n/a', f_int, (19,), dict(b=True)),
            ('n/a', f_int, (), dict(a=True, b=False))
        )
        assert_fail(self, known_exceptions)

    # float has type only (Complete)
    def test_good_float(self):
        """Float known good"""
        known_good = (
            (4.5, f_float, (2.0, 2.5), dict()),
            (4.5, f_float, (1.3,), dict(b=3.2)),
            (4.5, f_float, (), dict(a=5.9, b=-1.4))
        )
        assert_pass(self, known_good)

    def test_except_float(self):
        """Float exceptions"""
        known_exceptions = (
            ('n/a', f_float, (3, 4.0), dict()),
            ('n/a', f_float, (3.5,), dict(b=10)),
            ('n/a', f_float, (), dict(a=3, b='str'))
        )
        assert_fail(self, known_exceptions)

    # complex has type only (Complete)
    def test_good_complex(self):
        """Complex known good"""
        known_good = (
            (5 + 6j, f_complex, (3 + 3j, 2 + 3j), dict()),
            (5 + 6j, f_complex, (3 + 3j,), dict(b=2 + 3j)),
            (5 + 6j, f_complex, (), dict(a=3 + 3j, b=2 + 3j))
        )
        assert_pass(self, known_good)

    def test_except_complex(self):
        """Complex exceptions"""
        known_exceptions = (
            ('n/a', f_complex, (4, 3 + 10j), dict()),
            ('n/a', f_complex, (4,), dict(b=3 + 10j)),
            ('n/a', f_complex, (), dict(a=3 + 4j, b=True))
        )
        assert_fail(self, known_exceptions)

    # bytes has type only (Complete)
    def test_good_bytes(self):
        """Bytes known good"""
        known_good = (
            (b'test yes', f_bytes, (b'test', b' yes'), dict()),
            (b'test yes', f_bytes, (b'test',), dict(b=b' yes')),
            (b'test yes', f_bytes, (), dict(a=b'test', b=b' yes'))
        )
        assert_pass(self, known_good)

    def test_except_bytes(self):
        """Bytes exceptions"""
        known_exceptions = (
            ('n/a', f_bytes, (4, b'yes'), dict()),
            ('n/a', f_bytes, (b'test',), dict(b=' yes')),
            ('n/a', f_bytes, (), dict(a=b'test', b=True))
        )
        assert_fail(self, known_exceptions)

    # bytearray has type only (Complete)
    def test_good_bytearray(self):
        """Bytearray known good"""
        known_good = (
            (bytearray(b'test yes'), f_bytearray,
             (bytearray(b'test'), bytearray(b' yes')), dict()),
            (bytearray(b'test yes'), f_bytearray,
             (bytearray(b'test '),), dict(b=bytearray(b'yes'))),
            (bytearray(b'test yes'), f_bytearray,
             (), dict(a=bytearray(b'test'), b=bytearray(b' yes')))
        )
        assert_pass(self, known_good)

    def test_except_bytearray(self):
        """Bytearray exceptions"""
        known_exceptions = (
            (bytearray(b'n/a'), f_bytearray,
             (bytes(b'test'), bytearray(b' yes')), dict()),
            (bytearray(b'n/a'), f_bytearray,
             (bytearray(b'test '),), dict(b=bytes(b'yes'))),
            (bytearray(b'n/a'), f_bytearray,
             (), dict(a=b'test', b=bytearray(b' yes')))
        )
        assert_fail(self, known_exceptions)
    # Class has type and match only (Complete)
    # Note: that can't type check except with match

    def test_good_class(self):
        """Class known good"""
        t = BlankClass
        known_good = (
            ((t, t), f_Class, (BlankClass, BlankClass), dict()),
            ((t, t), f_Class, (BlankClass,), dict(b=BlankClass)),
            ((t, t), f_Class, (), dict(a=BlankClass, b=BlankClass))
        )
        assert_pass(self, known_good)

    def test_except_class(self):
        """Class exceptions"""
        known_exceptions = (
            ('n/a', f_Class, (BlankClass(3, 5),), dict(b=BlankClass)),
            ('n/a', f_Class, (4,), dict(b=6)),
            ('n/a', f_Class, (), dict(a=BlankClass, b=BlankClass(4, 5)))
        )
        assert_fail(self, known_exceptions)

    # ClassInst has type and match (Complete)
    # Note: can only check type against a match
    def test_good_classInst(self):
        """ClassInst known good"""
        t = BlankClass(30, 20)
        s = BlankClass(10, 20)
        known_good = (
            ((s, s), f_ClassInst,
             (t,), dict(b=t)),
            ((s, s), f_ClassInst,
             (t, t), dict()),
            ((s, s), f_ClassInst,
             (), dict(a=t, b=t))
        )
        for answer, func, args, kwargs in known_good:
            # Mapping needed to test that all instances from the same class
            l = list(map(lambda x, y: (x, y), answer, func(*args, **kwargs)))
            for results in l:
                self.assertEqual(results[0].__class__, results[1].__class__)

    def test_except_classInst(self):
        """ClassInst exceptions"""
        known_exceptions = (
            ('n/a', f_ClassInst, (BlankClass,), dict()),
            ('n/a', f_ClassInst, (5,), dict()),
            ('n/a', f_ClassInst, (BlankClass.functiontest(3, 5),), dict())
        )
        assert_fail(self, known_exceptions)

    # Func has type and match (Complete)

    def test_good_func_type(self):
        """Test checking if value is a function type"""
        known_good = (
            (basicfunc, f_Func_type, (basicfunc,), dict()),
            (twofuncy, f_Func_type, (), dict(a=twofuncy))
        )
        assert_pass(self, known_good)

    def test_except_func_type(self):
        """Test to check for exceptions on Func type"""
        known_exceptions = (
            ('n/a', f_Func_type, (4,), dict()),
            ('n/a', f_Func_type, (), dict(a=b'Hello'))
        )
        assert_fail(self, known_exceptions)

    def test_good_static_func(self):
        """Static Function known good"""
        t = BlankClass.functiontest
        known_good = (
            ((BlankClass.functiontest, BlankClass.functiontest), f_Func_static,
             (BlankClass.functiontest, BlankClass.functiontest), dict()),
            ((BlankClass.functiontest, BlankClass.functiontest), f_Func_static,
             (t,), dict(b=BlankClass.functiontest)),
            ((BlankClass.functiontest, BlankClass.functiontest), f_Func_static,
             (), dict(a=t, b=t))
        )
        assert_pass(self, known_good)

    def test_except_static_func(self):
        """Static Function exceptions"""
        known_exceptions = (
            ('n/a', f_Func_static,
             (BlankClass.functiontest, basicfunc), dict()),
            ('n/a', f_Func_static,
             (basicfunc, ), dict(b=BlankClass.functiontest))
        )
        assert_fail(self, known_exceptions)

    def test_good_functions(self):
        """Func known good"""
        t = basicfunc
        known_good = (
            (basicfunc, f_Func_match, (basicfunc,), dict()),
            (basicfunc, f_Func_match, (t,), dict()),
            (basicfunc, f_Func_match, (), dict(a=t))
        )
        assert_pass(self, known_good)

    def test_except_functions(self):
        """Func exceptions"""
        known_exceptions = (
            ('n/a', f_Func_match, (3,), dict()),
            ('n/a', f_Func_match, (), dict(a='failstring'))
        )
        assert_fail(self, known_exceptions)

    # Tuple has type, single, positional and group (Complete)
    def test_good_tuple_type(self):
        """Single Tuple (Without describing type)"""
        tup_test = tuple((4, 6, 7))
        known_good = (
            ((4, 6, 7), f_tuple_t, (tup_test,), dict()),
            ((4, 6, 7), f_tuple_t, (), dict(a=tup_test))
        )
        assert_pass(self, known_good)

    def test_except_tuple_type(self):
        """Single tuple exceptions"""
        known_exceptions = (
            ('n/a', f_tuple_t, ('ten'), dict()),
            ('n/a', f_tuple_t, (), dict(a='ten'))
        )
        assert_fail(self, known_exceptions)

    def test_good_tuple_single(self):
        """This tests a single int type within a tuple"""
        known_good = (
            ((4, 6, 7), f_tuple_s, ((4, 6, 7),), dict()),
            ((4, 6, 7), f_tuple_s, (), dict(a=(4, 6, 7)))
        )
        assert_pass(self, known_good)

    def test_except_tuple_single(self):
        """This tests failures for single int type within a tuple"""
        known_exceptions = (
            ('n/a', f_tuple_s, ((4, 6, 'string'),), dict()),
            ('n/a', f_tuple_s, (), dict(a=(4, 6, 'string')))
        )
        assert_fail(self, known_exceptions)

    def test_good_tuple_positional(self):
        """This tests positional annotation for tuples"""
        known_good = (
            ((10, 'Hello'), f_tuple_p, ((10, 'Hello'),), dict()),
            ((50, 'Yup!'), f_tuple_p, (), dict(a=(50, 'Yup!')))
        )
        assert_pass(self, known_good)

    def test_except_tuple_positional(self):
        """This tests failures for positional annotation for tuples"""
        known_exceptions = (
            ('n/a', f_tuple_p, (('Test broken', 20),), dict()),
            ('n/a', f_tuple_p, (), dict(a=(20, 30)))
        )
        assert_fail(self, known_exceptions)

    def test_good_tuple_multi(self):
        """This tests multiple types (int and str) in a tuple."""
        known_good = (
            ((4, 'Hello', 6), f_tuple_g, ((4, 'Hello', 6),), dict()),
            ((4, 'Hello', 6), f_tuple_g, (), dict(a=(4, 'Hello', 6)))
        )
        assert_pass(self, known_good)

    def test_except_tuple_multi(self):
        """This tests multiple type exceptions (int, str) in a tuple."""
        byte_string = 'Hello'.encode()
        known_exceptions = (
            ('n/a', f_tuple_g, ((4, byte_string, 6),), dict()),
            ('n/a', f_tuple_g, (), dict(a=(4, byte_string, 6)))
        )
        assert_fail(self, known_exceptions)

    # frozenset has type single and multiple (Complete)
    def test_good_frozenset_single_type(self):
        """This tests that the input was a frozenset"""
        default = frozenset([4, 5, 6, 'testing', b'byte_testing'])
        known_good = (
            (frozenset([4, 5, 6]), f_frozenset_t,
             (frozenset([4, 5, 6]),), dict()),
            (frozenset([4, 5, 6]), f_frozenset_t,
             (), dict(a=frozenset([4, 5, 6]))),
            (default, f_frozenset_t, (default, ), dict()),
            (default, f_frozenset_t, (), dict(a=default))
        )
        assert_pass(self, known_good)

    def test_except_frozenset_single_type(self):
        """This tests for frozenset single_type exceptions"""
        default = int(20)
        known_exceptions = (
            ('n/a', f_frozenset_t, (default,), dict()),
            ('n/a', f_frozenset_t, (), dict(a=default))
        )
        assert_fail(self, known_exceptions)

    def test_good_frozenset_multi_type(self):
        """This tests that the input was frozenset multi_type[int|str]"""
        default = frozenset([4, 5, 6, 'testing'])
        known_good = (
            (frozenset([4, 5, 6]), f_frozenset_g,
             (frozenset([4, 5, 6]),), dict()),
            (frozenset([4, 5, 6]), f_frozenset_g,
             (), dict(a=frozenset([4, 5, 6]))),
            (default, f_frozenset_g, (default, ), dict()),
            (default, f_frozenset_g, (), dict(a=default))
        )
        assert_pass(self, known_good)

    def test_except_frozenset_multi_type(self):
        """This tests for frozenset multi_type exceptions[int|str]"""
        default = int(20)
        known_exceptions = (
            ('n/a', f_frozenset_g, (default,), dict()),
            ('n/a', f_frozenset_g, (), dict(a=default))
        )
        assert_fail(self, known_exceptions)

    # Set has type and group (Complete)
    def test_good_set_single_type(self):
        """This tests that the input was a set"""
        default = set([4, 5, 6, 'testing', b'byte_testing'])
        known_good = (
            (set([4, 5, 6]), f_set_t, (set([4, 5, 6]),), dict()),
            (set([4, 5, 6]), f_set_t, (), dict(a=set([4, 5, 6]))),
            (default, f_set_t, (default, ), dict()),
            (default, f_set_t, (), dict(a=default))
        )
        assert_pass(self, known_good)

    def test_except_set_single_type(self):
        """This tests for set single_type exceptions"""
        default = int(20)
        known_exceptions = (
            ('n/a', f_set_t, (default,), dict()),
            ('n/a', f_set_t, (), dict(a=default))
        )
        assert_fail(self, known_exceptions)

    def test_good_set_multi_type(self):
        """This tests that the input was a set[int|str]"""
        default = set(['4', 5, 6, 'testing'])
        known_good = (
            (set([4, 'Hello', 6]), f_set_g, (set([4, 'Hello', 6]),), dict()),
            (set([4, 'Hello', 6]), f_set_g, (), dict(a=set([4, 'Hello', 6]))),
            (default, f_set_g, (default, ), dict()),
            (default, f_set_g, (), dict(a=default))
        )
        assert_pass(self, known_good)

    def test_except_set_multi_type(self):
        """This tests for set multi_type exceptions[int|str]"""
        default = set([4, 5, 6, 'testing', b'byte_testing'])
        known_exceptions = (
            ('n/a', f_set_g, (default,), dict()),
            ('n/a', f_set_g, (), dict(a=default))
        )
        assert_fail(self, known_exceptions)

    # List has type and group (Complete)
    def test_good_list_type(self):
        """This tests for list type"""
        known_good = (
            ([4, 5, 6], f_list_t, ([4, 5, 6],), dict()),
            (['4', '5', '6'], f_list_t, (), dict(a=['4', '5', '6']))
        )
        assert_pass(self, known_good)

    def test_except_list_type(self):
        """This tests list type for exceptions"""
        known_exceptions = (
            ('n/a', f_list_t, (5,), dict()),
            ('n/a', f_list_t, (), dict(a='string'))
        )
        assert_fail(self, known_exceptions)

    def test_good_list_p(self):
        """This tests for list positional"""
        known_good = (
            ([4, 'hello'], f_list_p, ([4, 'hello'],), dict()),
            ([10, 'string'], f_list_p, (), dict(a=[10, 'string']))
        )
        assert_pass(self, known_good)

    def test_except_list_p(self):
        """This tests exceptions for list positional annotations"""
        known_exceptions = (
            ('n/a', f_list_p, (['Wrong', 5],), dict()),
            ('n/a', f_list_p, (), dict(a=[4, 5]))
        )
        assert_fail(self, known_exceptions)

    def test_good_list_g(self):
        """This tests list type for iterating over types"""
        known_good = (
            ([4, 'Hello', 'World'], f_list_g,
             ([4, 'Hello', 'World'],), dict()),
        )
        assert_pass(self, known_good)

    def test_except_list_g(self):
        """This tests exceptions to the list types"""
        known_exceptions = (
            ('n/a', f_list_g, ([4, 'Hello', bytes(b'Test')],), dict()),
            ('n/a', f_list_g, (), dict(a=[4, 'Hello', 4.0]))
        )
        assert_fail(self, known_exceptions)

    def test_good_OrderedDict_t(self):
        """This tests OrderedDict types"""
        a = OrderedDict()
        for i, k in zip('abcdef', 'ghijk'):
            a.update({i: k})
        known_good = (
            (a, f_OrderedDict_t, (a,), dict()),
            (a, f_OrderedDict_t, (), dict(a=a)),
            # Confirm a is the first key (dict give 'd' first)
            # f_str takes (a, b='default') so result should be adefault
            ('adefault', f_str, ((a.__iter__().__next__()),), dict())
        )
        assert_pass(self, known_good)

    def test_except_OrderedDict_t(self):
        """This tests for exceptions of OrderedDict types"""
        known_exceptions = (
            ('n/a', f_OrderedDict_t, (45,), dict()),
            ('n/a', f_OrderedDict_t, (), dict(a=b'Testing'))
        )
        assert_fail(self, known_exceptions)

    # def f_OrderedDict_p(a: 'OrderedDict[str=int,bytes=str]')
    def test_good_OrderedDict_p(self):
        """This tests good ordering for OrderedDict positional"""
        a = OrderedDict()
        a.update({'string': 20})
        a.update({b'byteshash': 'Did you work?'})

        known_good = (
            (a, f_OrderedDict_p, (a,), dict()),
            (a, f_OrderedDict_p, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_OrderedDict_p(self):
        """Checking for known exceptions in OrderedDict positional"""
        a = OrderedDict()
        a.update({b'bytes should fail': 20})
        a.update({b'byteshash': 'Did you work?'})
        b = OrderedDict()
        b.update({'works': 20})
        b.update({b'Should fail': 30})

        known_exceptions = (
            # Test for KEY testing fail
            ('n/a', f_OrderedDict_p, (a,), dict()),
            ('n/a', f_OrderedDict_p, (), dict(a=a)),
            # Test for VALUE testing fail
            ('n/a', f_OrderedDict_p, (b,), dict()),
            ('n/a', f_OrderedDict_p, (), dict(a=b))
        )
        assert_fail(self, known_exceptions)

    def test_good_OrderedDict_g(self):
        """Tests OrderedDict group arguments."""
        # def f_OrderedDict_g(a: 'OrderedDict[str|bytes = bytes|int')
        a = OrderedDict()
        a.update({'First String': b'Bytes'})
        a.update({b'Bytes hash': 20})
        a.update({'String and int': 23})

        known_good = (
            (a, f_OrderedDict_g, (a, ), dict()),
            (a, f_OrderedDict_g, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_OrderedDict_g(self):
        """Checking for known exceptions in OrderedDict Group check"""
        a = OrderedDict()
        a.update({'Value String': 'Hello string fail'})
        a.update({10: b'Should fail on Key'})

        known_exceptions = (
            ('n/a', f_OrderedDict_g, (a,), dict()),
            ('n/a', f_OrderedDict_g, (), dict(a=a))
        )
        assert_fail(self, known_exceptions)

    def test_good_OrderedDict_key_only(self):
        """Tests OrderedDict for key only group"""
        a = OrderedDict()
        a.update({'String': 50})
        a.update({b'Bytes': b'Bytes again'})
        known_good = (
            (a, f_OrderedDict_key_only, (a,), dict()),
            (a, f_OrderedDict_key_only, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_OrderedDict_key_only(self):
        """Tests exceptions for OrderedDict key only"""
        a = OrderedDict()
        a.update({40: 'int'})
        b = OrderedDict()
        b.update({'String': 'next fails'})
        b.update({50: 'This should fail'})

        known_exceptions = (
            ('n/a', f_OrderedDict_key_only, (a,), dict()),
            ('n/a', f_OrderedDict_key_only, (b,), dict()),
            ('n/a', f_OrderedDict_key_only, (), dict(a=a)),
            ('n/a', f_OrderedDict_key_only, (), dict(a=b))
        )
        assert_fail(self, known_exceptions)

    def test_good_OrderedDict_value_only(self):
        """Tests OrderedDict for value only group"""
        a = OrderedDict()
        a.update({50: 50})
        a.update({60: b'bytes should work'})

        known_good = (
            (a, f_OrderedDict_value_only, (a,), dict()),
            (a, f_OrderedDict_value_only, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_OrderedDict_value_only(self):
        """Tests OrdererDict exceptions fro value only group"""
        a = OrderedDict()
        b = OrderedDict()
        a.update({'String': 'Fail String'})
        b.update({'String': b'Successful'})
        b.update({'Fail key': 'Fail String'})

        known_exceptions = (
            ('n/a', f_OrderedDict_value_only, (a,), dict()),
            ('n/a', f_OrderedDict_value_only, (b,), dict()),
            ('n/a', f_OrderedDict_value_only, (), dict(a=a)),
            ('n/a', f_OrderedDict_value_only, (), dict(a=b))
        )
        assert_fail(self, known_exceptions)

    def test_good_dict_t(self):
        """Test dict for type."""
        a = {}
        for i, k in zip('abcdefg', 'hijkmn'):
            a.update({i: k})

        known_good = (
            (a, f_dict_t, (a,), dict()),
            (a, f_dict_t, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_dict_t(self):
        """Test dict exceptions for type."""
        known_exceptions = (
            ('n/a', f_dict_t, (b'Fail bytes',), dict()),
            ('n/a', f_dict_t, (), dict(a='l33t fail'))
        )
        assert_fail(self, known_exceptions)

    def test_good_dict_group(self):
        """Test dict groups for dict[str=int]"""
        a = {}
        a.update({'Should be good': 200})
        a.update({'Redirect': 304})

        known_good = (
            (a, f_dict_g, (a,), dict()),
            (a, f_dict_g, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_dict_group(self):
        """Test exceptions for dict groups for dict[str=int]"""
        a = {}
        a.update({'This shouldn\'t fail': 200})
        a.update({'This should fail': b'Broken'})

        known_exceptions = (
            ('n/a', f_dict_g, (a,), dict()),
            ('n/a', f_dict_g, (), dict(a=a))
        )
        assert_fail(self, known_exceptions)

    def test_good_dict_key_only(self):
        """Tests dict for key only check dict[str|bytes]"""
        a = {}
        a.update({'This should work': 200})
        a.update({b'Now bytes': b'Does not check'})

        known_good = (
            (a, f_dict_key_only, (a,), dict()),
            (a, f_dict_key_only, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_dict_key_only(self):
        """Tests exceptions for key only check dict[str|bytes]"""
        a = {}
        a.update({'Should not fail': 200})
        a.update({401: 'This one fails'})

        known_exceptions = (
            ('n/a', f_dict_key_only, (a,), dict()),
            ('n/a', f_dict_key_only, (), dict(a=a))
        )
        assert_fail(self, known_exceptions)

    def test_good_dict_value_only(self):
        """Tests dict for value only checks dict[=int|bytes]"""
        a = {}
        for i, k in zip('abcd', [10, b'bytes', 200, b'Next bytes']):
            a.update({i: k})

        known_good = (
            (a, f_dict_value_only, (a,), dict()),
            (a, f_dict_value_only, (), dict(a=a))
        )
        assert_pass(self, known_good)

    def test_except_dict_value_only(self):
        """Tests exceptions for value only checks dict[=int|bytes]"""
        a = {}
        for i, k in zip('abcd', [10, 20, 30, 'Add string to break']):
            a.update({i: k})

        known_exceptions = (
            ('n/a', f_dict_value_only, (a,), dict()),
            ('n/a', f_dict_value_only, (), dict(a=a))
        )
        assert_fail(self, known_exceptions)

    def test_good_namedtuple_t(self):
        """Tests namedtuple type check"""
        n = tupname(1, 2, 3)
        m = tupname('Hello', 'Next', 'Third')
        known_good = (
            (n, f_namedtuple_t, (n,), dict()),
            (n, f_namedtuple_t, (), dict(a=n)),
            (m, f_namedtuple_t, (m,), dict()),
            (m, f_namedtuple_t, (), dict(a=m))
        )
        assert_pass(self, known_good)

    def test_except_namedtuple_t(self):
        """Tests exceptions for type check"""
        n = (4, 5, 6)
        m = ['String', 'Next']
        known_exceptions = (
            ('n/a', f_namedtuple_t, (n,), dict()),
            ('n/a', f_namedtuple_t, (m,), dict()),
            ('n/a', f_namedtuple_t, (), dict(a=n)),
            ('n/a', f_namedtuple_t, (), dict(a=m))
        )
        assert_fail(self, known_exceptions)

    def test_good_namedtuple_n(self):
        """Tests namedtuple matching tupname check"""
        tupname = namedtuple('tupname', ('one', 'two', 'three'))
        n = tupname(1, 2, 3)
        known_good = (
            (n, f_namedtuple_n, (n,), dict()),
            (n, f_namedtuple_n, (), dict(a=n))
        )
        assert_pass(self, known_good)

    def test_except_namedtuple_n(self):
        """Tests exceptions for namedtuple name check"""
        n = dif_namedtuple(4, 5, 6)
        m = ['String', 'Next']
        known_exceptions = (
            ('n/a', f_namedtuple_n, (n,), dict()),
            ('n/a', f_namedtuple_n, (m,), dict()),
            ('n/a', f_namedtuple_n, (), dict(a=n)),
            ('n/a', f_namedtuple_n, (), dict(a=m))
        )
        assert_fail(self, known_exceptions)

    def test_good_namedtuple_p(self):
        """Tests namedtuple with positional arguments"""
        n = tupname(1, b'2', '3')
        m = tupname(200, b'Next', 'Third')
        known_good = (
            (n, f_namedtuple_p, (n,), dict()),
            (n, f_namedtuple_p, (), dict(a=n)),
            (m, f_namedtuple_p, (m,), dict()),
            (m, f_namedtuple_p, (), dict(a=m))
        )
        assert_pass(self, known_good)

    def test_except_namedtuple_p(self):
        """Tests exceptions for namedtuple with positional type check"""
        n = tupname(1.2, b'2', '3')
        m = tupname(200, b'Next', b'Third')
        known_exceptions = (
            ('n/a', f_namedtuple_p, (n,), dict()),
            ('n/a', f_namedtuple_p, (m,), dict()),
            ('n/a', f_namedtuple_p, (), dict(a=n)),
            ('n/a', f_namedtuple_p, (), dict(a=m))
        )
        assert_fail(self, known_exceptions)

    def test_good_namedtuple_g(self):
        """Tests namedtuple with group arguments"""
        n = tupname(1, '2', '3')
        m = tupname('200', 300, 'Third')
        known_good = (
            (n, f_namedtuple_g, (n,), dict()),
            (n, f_namedtuple_g, (), dict(a=n)),
            (m, f_namedtuple_g, (m,), dict()),
            (m, f_namedtuple_g, (), dict(a=m))
        )
        assert_pass(self, known_good)

    def test_except_namedtuple_g(self):
        """Tests exceptions for namedtuple with group type check"""
        n = tupname(1.2, b'2', '3')
        m = tupname(200, b'Next', b'Third')
        known_exceptions = (
            ('n/a', f_namedtuple_g, (n,), dict()),
            ('n/a', f_namedtuple_g, (m,), dict()),
            ('n/a', f_namedtuple_g, (), dict(a=n)),
            ('n/a', f_namedtuple_g, (), dict(a=m))
        )
        assert_fail(self, known_exceptions)

if __name__ == '__main__':

    parser = argparse.ArgumentParser(
        description='Unit Tests for annotate_test.')
    parser.add_argument('--debug', dest='debug', action='store_true',
                        help='Debug of returns from exceptions')

    args = parser.parse_args()
    print(args)
    if args.debug is True:
        debug_except = 'Y'
    else:
        debug_except = 'N'

    del args
    #    unittest.main() - Previous command before fixing unittest
    # Below is needed because unittest tries to resolve custom args.

    runner = unittest.TextTestRunner()
    itersuite = unittest.TestLoader().loadTestsFromTestCase(AnnotationTester)
    runner.run(itersuite)


import pytest

import pickle

import pandas as pd

from daskperiment.backend import MongoBackend, RedisBackend
from daskperiment.backend.mongo import MongoKey

class NoSQLBase(object):

    @classmethod
    def init_backend(cls):
        raise NotImplementedError

    def make_key(self, key):
        """
        Create key to backend
        """
        return key

    def make_expected(self, exp):
        """
        Convert expected input to DB internal repr
        """
        return exp

    @classmethod
    def teardown_class(cls):
        backend = cls.init_backend()
        backend._delete_cache()

    def test_set_get(self):
        backend = self.init_backend()

        key = self.make_key('test_key')
        backend.set(key, 0)
        assert backend.get(key) == self.make_expected(0)

    def test_get_not_exist(self):
        backend = self.init_backend()
        key = self.make_key('no_key')
        assert backend.get(key) is None

    @pytest.mark.parametrize('key_string', ['list_key', 'dot_list_key.child',
                                            'num_list_key.series.1'])
    def test_append_list(self, key_string):
        backend = self.init_backend()

        key = self.make_key(key_string)
        backend.append_list(key, 10)
        assert backend.get_list(key) == self.make_expected([10])

        backend.append_list(key, 20)
        assert backend.get_list(key) == self.make_expected([10, 20])

        backend.append_list(key, 30)
        backend.append_list(key, 40)
        assert backend.get_list(key) == self.make_expected([10, 20, 30, 40])

        new_key = self.make_key(key_string + '2')
        backend.append_list(new_key, 1)
        assert backend.get_list(new_key) == self.make_expected([1])
        assert backend.get_list(key) == self.make_expected([10, 20, 30, 40])

    def test_no_list_key(self):
        backend = self.init_backend()
        key = self.make_key('no_list')
        assert backend.get_list(key) == []
        assert backend.get(key) is None

    def test_increment(self):
        backend = self.init_backend()

        key = self.make_key('incr_key')
        assert backend.increment(key) == 1
        assert backend.increment(key) == 2
        assert backend.increment(key) == 3
        assert backend.increment(key) == 4

        new_key = self.make_key('new_incr_key')
        assert backend.increment(new_key) == 1
        assert backend.increment(key) == 5

    def test_save_load_text(self):
        backend = self.init_backend()

        key = self.make_key('text_key')
        backend.save_text(key, 'aaa')
        assert backend.load_text(key) == 'aaa'

        backend.save_text(key, 'bbb')
        assert backend.load_text(key) == 'bbb'

    @pytest.mark.parametrize('key_string', ['obj_key', 'num_obj_key.series.1'])
    def test_save_load_object(self, key_string):
        backend = self.init_backend()
        obj = {'a': 1, 'b': pd.Timestamp('2011-01-01')}

        key = self.make_key(key_string)
        backend.save_object(key, obj)
        assert backend.load_object(key) == obj

    def test_pickle_roundtrip_save_load_object(self):
        backend = self.init_backend()

        pickle_obj_key = self.make_key('pickle_obj_key')
        obj = {'a': 1, 'b': pd.Timestamp('2011-01-01')}
        backend.save_object(pickle_obj_key, obj)
        assert backend.load_object(pickle_obj_key) == obj

        pickle_text_key = self.make_key('pickle_text_key')
        backend.save_object(pickle_text_key, 'xxxx')
        assert backend.load_object(pickle_text_key) == 'xxxx'

        new_backend = pickle.loads(pickle.dumps(backend))
        assert new_backend.load_object(pickle_obj_key) == obj
        assert new_backend.load_object(pickle_text_key) == 'xxxx'

        assert backend.load_object(pickle_obj_key) == obj
        assert backend.load_object(pickle_text_key) == 'xxxx'

class TestRedisBackend(NoSQLBase):

    @classmethod
    def init_backend(cls):
        uri = 'redis://localhost:6379/0'
        return RedisBackend('redis_backend', uri)

    def make_expected(self, exp):
        if isinstance(exp, int):
            return str(exp).encode()
        elif isinstance(exp, list):
            return [self.make_expected(e) for e in exp]
        else:
            raise NotImplementedError

class TestMongoBackend(NoSQLBase):

    @classmethod
    def init_backend(cls):
        uri = 'mongodb://localhost:27017/test_db'
        return MongoBackend('mongo_backend', uri)

    def make_key(self, key):
        return MongoKey({'test_mongo_key': key})

    def test_mongo_key(self):
        backend = self.init_backend()

        key = MongoKey({'experiment_id': 'test_mongo_key',
                        'trial_id': 1})

        backend.set(key, 100)
        assert backend.get(key) == 100
        backend.set(key, 200)
        assert backend.get(key) == 200

        new_key = MongoKey({'experiment_id': 'test_mongo_key',
                            'trial_id': 2})

        backend.set(new_key, 300)
        assert backend.get(new_key) == 300
        assert backend.get(key) == 200

    def test_mongo_key_internal(self):
        backend = self.init_backend()

        key = MongoKey({'experiment_id': 'test_mongo_key_internal',
                        'trial_id': 1354,
                        'internal_unique_key': 'xxxxx'})

        backend.set(key, 100)
        assert backend.get(key) == 100

        key = MongoKey({'internal_unique_key': 'xxxxx'},
                       field_name='experiment_id')
        assert backend.get(key) == 'test_mongo_key_internal'

        key = MongoKey({'internal_unique_key': 'xxxxx'},
                       field_name='trial_id')
        assert backend.get(key) == 1354

    def test_append_list_mongo_key(self):
        backend = self.init_backend()

        key = MongoKey({'experiment_id': 'test_append_list_mongo_key',
                        'trial_id': 1})

        backend.append_list(key, 10)
        assert backend.get_list(key) == [10]

        backend.append_list(key, 20)
        assert backend.get_list(key) == [10, 20]

    def test_increment_mongo_key(self):
        backend = self.init_backend()

        key = MongoKey({'experiment_id': 'test_increment_mongo_key',
                        'trial_id': 1})

        assert backend.increment(key) == 1
        assert backend.increment(key) == 2
        assert backend.increment(key) == 3
        assert backend.increment(key) == 4

        new_key = MongoKey({'experiment_id': 'test_increment_mongo_key',
                            'trial_id': 2})
        assert backend.increment(new_key) == 1
        assert backend.increment(key) == 5

class TestMongoKey(object):

    def test_eq(self):
        key1 = MongoKey({'doc': 1, 'id': 2})
        key2 = MongoKey({'doc': 1, 'id': 2})
        assert key1 == key2

        key3 = MongoKey({'doc': 1, 'id': 3})
        assert key1 != key3

        key4 = MongoKey({'doc': 1, 'id': 2}, field_name='xxx')
        assert key1 != key4
        assert key2 != key4

    def test_repr(self):
        key = MongoKey({'doc': 1, 'id': 2})
        exp = "MongoKey(meta={'doc': 1, 'id': 2}, field_name=value)"
        assert repr(key) == exp

    def test_wildcard(self):
        key = MongoKey({'key1': 1, 'key2': 2, 'key3': '*'})
        assert key.document_meta == {'key1': 1, 'key2': 2}


"""
SuperScript network module
===========

Classes:
    SocialNetwork
        Class for tracking social network of collaborations
"""

import networkx as nx
from itertools import combinations
from mesa.space import NetworkGrid

from .config import HISTORICAL_SUCCESS_RATIO_THRESHOLD

class SocialNetwork(NetworkGrid):
    """Social network class.

    Is a subclass of mesa.space.NetworkGrid

    Edges in this network count the number of successful collaborations
    between each pair of workers.
    ...

    Attributes:
        model: model.SuperScriptModel
            Reference to main model.
        G: nx.Graph
            Networkx x graph object, created in main model.
        success_threshold: float
            Fraction of team members who need to have worked before on
            successful project for get_team_historical_success_flag to
            return True.
    """

    def __init__(self, model, G,
                 success_threshold=HISTORICAL_SUCCESS_RATIO_THRESHOLD):

        self.model = model
        self.G = G
        self.success_threshold = success_threshold

    def initialise(self):
        """Create the network.

        Adds all workers as nodes in the network.
        Calls base class constructor and calls base class method
        to place each worker on their node.
        """

        for worker in self.model.schedule.agents:
            self.G.add_node(
                worker.worker_id,
                department=worker.department.dept_id
            )
        super().__init__(self.G)

        for worker, node in zip(self.model.schedule.agents, self.G.nodes()):
            self.place_agent(worker, node)

    def replace_worker(self, old_worker, new_worker):
        """Replaces worker in the network (called when a worker is
        replaced due to inactivity.

        Args:
            old_worker: worker.Worker
                Worker being replace.
            new_worker: worker.Worker
                Worker replacing old worker.
        """

        self._remove_agent(old_worker, old_worker.worker_id)
        self.G = nx.relabel_nodes(
            self.G,
            {old_worker.worker_id: new_worker.worker_id},
            copy=False
        )
        self.place_agent(new_worker, new_worker.worker_id)

    def add_team_edges(self, team):
        """Adds all edges between pairs of workers in this team.

        If an edge already exists, its weight is incremented by 1.

        Args:
            team: organisation.Team
                Provides list of members that have successfully
                collaborated on a project and are to be added
                to the network.
        """

        pairs = list(combinations(team.members.keys(), 2))
        for pair in pairs:

            if (pair[0], pair[1]) not in self.G.edges():
                self.G.add_edge(pair[0], pair[1], weight=1)
            else:
                self.G[pair[0]][pair[1]]['weight'] += 1

    def get_team_historical_success_flag(self, team):
        """Determine is team meets required threshold for previous
        successful collaboration.

        Args:
            team: organisation.Team

        Returns:
            bool: True if more than self.success_threshold of possible
                  edges are realised in this network.
        """

        pairs = list(combinations(team.members.keys(), 2))
        success_ratio = 0
        for pair in pairs:
            if (pair[0], pair[1]) in self.G.edges():
                success_ratio += 1

        success_ratio = (
            success_ratio / len(pairs) if len(pairs) > 0 else 0.0
        )
        if success_ratio >= self.success_threshold:
            return True
        else:
            return False

    def save(self):
        """Save network for later analysis."""
        nx.write_gpickle(
            self.G,
            self.model.io_dir
            + '/network_timestep_%d.gpickle' % self.model.time
        )


from collections import deque
from aiomeasures.events import Event

class Collector(deque):
    """Caped list of metrics
    """

    def flush(self, rate=None, formatter=None):
        while True:
            try:
                metric = self.popleft()
                if isinstance(metric, Event):
                    yield formatter(metric)
                    continue
                if metric.value is None:
                    continue
                if rate and metric.rate and rate < metric.rate:
                    continue
                if formatter:
                    try:
                        yield formatter(metric)
                    except ValueError:
                        continue
                else:
                    yield metric
            except IndexError:
                raise StopIteration


import numpy as np
from scipy.ndimage import rotate
from scipy.signal import convolve2d
import math
from .dataReader import DataReader
import imutils
from PIL import Image
from math import ceil
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

def conv2(x, y, mode='same'):
    """
    Convoles two images similar to MATLAB's convolution'
    Args:
        x (_numpy_arr_): _First arr to convolve_
        y (_numpy_arr_): _Second array to convolve with_
        mode (str, optional): Defaults to 'same'.

    Returns:
        _type_: _description_
    """
    return np.rot90(convolve2d(np.rot90(x, 2), np.rot90(y, 2), mode=mode), 2)

class OptimizationFunction:
    """
    Optimization reated functions to align the coarse image exactly with fine image
    """
    def optima(self, inputs, coarse_image, fine_image, edge, N):
        """
        RMSE cost Function to be used for optimization and obtain parameters
        Args:
            inputs (_list_): _Swarm positions for optimization_
            coarse_image (_numpy_array_): _Band from coarse image_
            fine_image (_numpy array_): _Band from fine image_
            edge (_int_): _Difference between the size of coarse and fine image_
            N (_int_): _Size of fine image_

        Returns:
            _list_: _Cost from each swarm position_
        """
        inputs = np.array(inputs)
        cost = []

        # Process for each particle position
        for i  in range(len(inputs)):

            # Apply FFT on image and use RMSE for optimization
            filtered_CoarseImage = self.FFT(inputs[i], coarse_image, edge, N)
            cost.append(np.sqrt(np.mean(np.power(filtered_CoarseImage - fine_image, 2))))

        cost = np.array(cost).T
        return cost

    def FFT(self, parameters, image, edge, N):
        """
        FFT function which applies PSF and finds appropraites portion from complete coarse image
        Args:
            parameters (_list_): _Parameters for applying PSF and shifting_
            image (_numpy_arr_): _Numpy array of image_
            edge (_int_): _Difference between the coarse and fine image_
            N (_int_): _Size of the fine image_

        Returns:
            _numpy_arr_: _coarse image which aligns to fine image_
        """
        fwhm_x = parameters[0]
        fwhm_y = parameters[1]
        sh_x = parameters[2]
        sh_y = parameters[3]
        angle = parameters[4]

        # Calculate SMF for given parameters
        psf_cal = self.SMF(fwhm_x, fwhm_y, angle)

        # convolve image with PSF
        image_fft = conv2(image, psf_cal, 'same')
        ends = list(image_fft.shape)

        # Cut the coarse image such that it aligns with the fine image exactly
        image_fft = image_fft[int(edge + sh_y): int(ends[0] - edge + sh_y), int(edge + sh_x): int(ends[1]-edge + sh_x)]
        return image_fft.reshape(1, (N * N))

    def SMF(self, fwhm_x, fwhm_y, angle):
        """
        SMF obtains the PSF and creates the appropraite mask and rotates for it to align exactly
        Args:
            fwhm_x (_int_): _accomodates for PSF in X direction_
            fwhm_y (_int_): _accomodates for PSF in Y direction_
            angle (_int_): _rotates the PSF_

        Returns:
            _numpy_arr_: _rotated PSF array_
        """

        # Obtain PSF
        psf_gaussian = self.PSF(fwhm_x, fwhm_y)
        psf_mask = np.zeros_like(psf_gaussian)

        # PSF Mask
        psf_mask[int(ceil(fwhm_y/2)) : int(ceil(2*fwhm_y-(fwhm_y/2))) + 1, int(ceil(fwhm_x/2)) : int(ceil(2 * fwhm_x - (fwhm_x/2))) +1] = 1

        # Rotate MASK and the gaussian in counter clockwise direction
        rot_psf_mask = np.array(Image.fromarray(psf_mask).rotate(angle = angle, expand = True))
        psf_gaussian = np.array(Image.fromarray(psf_gaussian).rotate(angle = angle, expand = True))

        psf_gaussian[np.where(rot_psf_mask == 0)] = 0
        rowpix, colpix = np.where(rot_psf_mask == 1)

        # Cut the required portion of PSF which actually has an impact
        psf = psf_gaussian[np.min(rowpix):np.max(rowpix) + 1, np.min(colpix):np.max(colpix) + 1]
        psf = psf / np.sum(psf)

        # Normalize and return the final PSF
        return np.round(psf, 4)

    def PSF(self, fwhm_x, fwhm_y):
        """
        PSF for accomodating change in pixels because of sensor observations
        Args:
            fwhm_x (_int_): _Useful for defining x side of pixel change effects_
            fwhm_y (_int_): _Useful for defining y side of pixel change effects_

        Returns:
            _numpy_arr_: _PSF array by modelling using gaussian function_
        """
        # TODO : Fix and try to check if it's opposite
        sd_x = fwhm_x / (2 * math.sqrt(2 * math.log(2)))
        sd_y = fwhm_y / (2 * math.sqrt(2 * math.log(2)))

        x_max = fwhm_x * 2
        y_max = fwhm_y * 2

        # Gaussian Function for both x and y
        gaussian_x = np.matrix(self.gaussian(x_max + 1, sd_x))
        gaussian_y = np.matrix(self.gaussian(y_max + 1, sd_y))
        gaussian_xy = np.matmul(gaussian_y.getH(), gaussian_x)

        # Combination of both gaussians
        psf = gaussian_xy / (np.sum(gaussian_xy))
        psf = np.round(psf, 4)
        return psf

    def gaussian(self, M, std):
        """
        Gaussian Function used to account for PSF
        Args:
            M (_float_): _Mean of the Gaussian distribution_
            std (_float_): _Standard Deviation of the Gaussian distribution_

        Returns:
            _numpy_arr_
        """
        Mn = (M - 1)/2
        n = np.array([i for i in range(-int(Mn), int(Mn) + 1, 1)])
        gwin = np.exp(-0.5*np.power((n/std), 2))
        return gwin


from django import template
from brandapp.models import *

from django.contrib.auth.models import User
register = template.Library()

@register.filter
def check_temp(val):
	try:
		temp=emailTemplate.objects.get(category=val)
		print("False")
		return False
	except Exception as e:
		print("True")
		return True


import re

def get_vocabs(filename, allvocabs):
    """
    :param filename: name of the file
    :param contents:
    :param allvocabs:
    :return:
    """
    with open("data/" + filename) as f:
        contents = f.readlines()
        vocabs = set()
        contents = [re.sub(r'\W+', " ", content).strip() for content in contents]
        words_lists = [re.split("\s+|,\s+", content) for content in contents]

        for words in words_lists:
            vocabs.update(words)

        print(filename , "has" , len(vocabs) , "unique vocabs")
        allvocabs = allvocabs.union(vocabs)

    return allvocabs

if __name__ == "__main__":

    english_vocabs = set()
    german_vocabs = set()

    german_vocabs = get_vocabs("dev.de", german_vocabs)
    english_vocabs = get_vocabs("dev.en", english_vocabs)
    german_vocabs = get_vocabs("train.de", german_vocabs)
    english_vocabs = get_vocabs("train.en", english_vocabs)

    print(len(english_vocabs), "unique english vocabs")
    print(len(german_vocabs), "unique english vocabs")


file = open("input.txt", "r")
myin = [line.strip() for line in file.readlines()]
file.close()

def follow(t, h):
    x = h[1] - t[1]
    y = h[0] - t[0]

    if abs(x) < 2 and abs(y) < 2:
        return t
    elif abs(x) == 2 and y == 0:
        t[1] += x//abs(x)
    elif abs(y) == 2 and x == 0:
        t[0] += y // abs(y)
    else:
        t[1] += x // abs(x)
        t[0] += y // abs(y)

    return t

def part_one():
    T = [4, 0]
    H = [4, 0]
    pos = []

    for line in myin:
        for i in range(int(line[line.index(" ") + 1:])):

            if line[0] == "L":
                H[1] -= 1
            elif line[0] == "R":
                H[1] += 1

            if line[0] == "U":
                H[0] -= 1
            elif line[0] == "D":
                H[0] += 1

            T = follow(T, H)
            pos.append(str(T[0]) + "," + str(T[1]))

    print(len(set(pos)))

def part_two():
    T1 = [4, 0]
    T2 = [4, 0]
    T3 = [4, 0]
    T4 = [4, 0]
    T5 = [4, 0]
    T6 = [4, 0]
    T7 = [4, 0]
    T8 = [4, 0]
    T9 = [4, 0]
    H = [4, 0]
    pos = []

    for line in myin:
        for i in range(int(line[line.index(" ") + 1:])):

            if line[0] == "L":
                H[1] -= 1
            elif line[0] == "R":
                H[1] += 1

            if line[0] == "U":
                H[0] -= 1
            elif line[0] == "D":
                H[0] += 1

            T1 = follow(T1, H)
            T2 = follow(T2, T1)
            T3 = follow(T3, T2)
            T4 = follow(T4, T3)
            T5 = follow(T5, T4)
            T6 = follow(T6, T5)
            T7 = follow(T7, T6)
            T8 = follow(T8, T7)
            T9 = follow(T9, T8)

            pos.append(str(T9[0]) + "," + str(T9[1]))
    print(len(set(pos)))

part_one()
part_two()


import os
import json
import yaml
import scipy
import pickle
import numpy as np
from copy import deepcopy
from torch.utils.data import Dataset

from utils import read_nifti

class Geometry(object):
    def __init__(self, config):
        self.v_res = config['nVoxel'][0]    # ct scan
        self.p_res = config['nDetector'][0] # projections
        self.v_spacing = np.array(config['dVoxel'])[0]    # mm
        self.p_spacing = np.array(config['dDetector'])[0] # mm

        self.DSO = config['DSO'] # mm
        self.DSD = config['DSD'] # mm

    def project(self, points, angle):
        # points: [N, 3] ranging from [0, 1]
        # d_points: [N, 2] ranging from [-1, 1]

        points = deepcopy(points).astype(float)
        points[:, :2] -= 0.5 # [-0.5, 0.5]
        points[:, 2] = 0.5 - points[:, 2] # [-0.5, 0.5]
        points *= self.v_res * self.v_spacing # mm

        angle = -1 * angle # inverse direction
        rot_M = np.array([
            [np.cos(angle), -np.sin(angle), 0],
            [np.sin(angle),  np.cos(angle), 0],
            [            0,              0, 1]
        ])
        points = points @ rot_M.T

        d1 = self.DSO
        d2 = self.DSD

        coeff = (d2) / (d1 - points[:, 0]) # N,
        d_points = points[:, [2, 1]] * coeff[:, None] # [N, 2] float
        d_points /= (self.p_res * self.p_spacing)
        d_points *= 2 # NOTE: some points may fall outside [-1, 1]

        return d_points

class Mixed_CBCT_dataset(Dataset):
    def __init__(self, dst_list, **kwargs) -> None:
        super().__init__()
        print('mixed_dataset:', dst_list)
        self.name_list = dst_list
        self.datasets = []
        for dst_name in self.name_list:
            self.datasets.append(CBCT_dataset(dst_name, **kwargs))

    def __len__(self):
        dst_len = [len(d) for d in self.datasets]
        return np.sum(dst_len)

    @property
    def num_dst(self):
        return len(self.datasets)

    def find_dst(self, index):
        for i, dst in enumerate(self.datasets):
            if index >= len(dst):
                index -= len(dst)
            else:
                return i, index

    def __getitem__(self, index):
        dst_idx, index = self.find_dst(index)

        dst_vec = np.zeros(self.num_dst)
        dst_vec[dst_idx] = 1.

        data_dict = self.datasets[dst_idx][index]
        data_dict['dst_vec'] = dst_vec
        data_dict['dst_name'] = self.name_list[dst_idx]
        return data_dict

class CBCT_dataset(Dataset):
    def __init__(
            self,
            dst_name,
            split='train',
            num_views=10,
            npoint=5000,
            out_res=256,
            random_views=False,
            view_offset=0
        ):
        super().__init__()
        dst_root = './data'

        # load dataset info
        if dst_name in ['knee_cbct']:
            data_root = os.path.join(dst_root, dst_name)
            with open(os.path.join(data_root, 'info.json'), 'r') as f:
                cfg = json.load(f)
                name_list = sorted(cfg[split])
                print('CBCT_dataset, name: {}, split: {}, len: {}.'.format(dst_name, split, len(name_list)))
        else:
            raise ValueError(dst_name)

        # load projection config
        with open(os.path.join(data_root, cfg['projection_config']), 'r') as f:
            proj_cfg = yaml.safe_load(f)
            self.geo = Geometry(proj_cfg)

        # prepare points
        if split == 'train':
            # load blocks' coordinates [train only]
            self.blocks = np.load(os.path.join(data_root, cfg['blocks']))
        else:
            # prepare sampling points
            points = np.mgrid[:out_res, :out_res, :out_res]
            points = points.astype(float) / (out_res - 1)
            points = points.reshape(3, -1)
            self.points = points.transpose(1, 0) # N, 3

        # other parameters
        self.out_res = out_res
        self.data_root = data_root
        self.cfg = cfg

        self.name_list = name_list
        self.npoint = npoint
        self.is_train = (split == 'train')
        self.num_views = num_views
        self.random_views = random_views
        self.view_offset = view_offset

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

    def sample_projections(self, name):
        # -- load projections
        with open(os.path.join(self.data_root, self.cfg['projections'].format(name)), 'rb') as f:
            data = pickle.load(f)
            projs = data['projections'] # K, 1, res^2
            angles = data['angles']     # K,

        # -- sample projections
        views = np.linspace(0, len(projs), self.num_views, endpoint=False).astype(int)
        offset = np.random.randint(len(projs) - views[-1]) if self.random_views else self.view_offset
        views += offset
        projs = projs[views].astype(float) / 255.
        projs = projs[:, None, ...]
        angles = angles[views]

        # -- de-normalization [required for mixed dataset]
        # projs = projs * self.cfg['projection_norm'] / 0.2

        return projs, angles

    def load_ct(self, name):
        image = read_nifti(os.path.join(self.data_root, self.cfg['image'].format(name)))
        image = image.astype(np.float32) / 255.
        if self.out_res == 128:
            image = scipy.ndimage.zoom(image, 0.5, order=3, prefilter=False)
        elif self.out_res != 256:
            raise ValueError
        return image

    def load_block(self, name, b_idx):
        path = os.path.join(self.data_root, self.cfg['image_block'].format(name, b_idx))
        return np.load(path)

    def sample_points(self, points, values=None):
        choice = np.random.choice(len(points), size=self.npoint, replace=False)
        points = points[choice]
        if values is not None:
            values = values[choice]
            values = values.astype(float) / 255.
            return points, values
        else: return points

    def __getitem__(self, index):
        name = self.name_list[index]

        # -- load projections
        projs, angles = self.sample_projections(name)

        # -- load sampling points
        if not self.is_train:
            points = self.points
            image = self.load_ct(name)
            p_gt = np.zeros(len(points))
        else:
            b_idx = np.random.randint(len(self.blocks))
            block_values = self.load_block(name, b_idx)
            block_coords = self.blocks[b_idx] # N, 3
            points, p_gt = self.sample_points(block_coords, block_values)

        # -- project points and view direction
        proj_points = []
        for a in angles:
            p = self.geo.project(points, a)
            proj_points.append(p)
        proj_points = np.stack(proj_points, axis=0) # M, N, 2

        # -- normalize points
        points = deepcopy(points) # ~[0, 1]
        points[:, :2] -= 0.5 # [-0.5, 0.5]
        points[:, 2] = 0.5 - points[:, 2] # [-0.5, 0.5]
        points *= 2 # => [-1, 1]

        # -- normalize viewing angles
        angles = np.array(angles, dtype=float) # ~[0, +pi]
        angles = angles / np.pi * 2 - 1 # => [-1, 1]

        # -- collect data
        ret_dict = {
            'name': name,
            'points': points,           # 3D points
            'angles': angles[:, None],  # angles
            'proj_points': proj_points, # projected points
            'projs': projs,             # 2D projections
            'p_gt': p_gt[None, :]       # labels
        }
        if not self.is_train:
            ret_dict['image'] = image

        return ret_dict

if __name__ == '__main__':
    dst = CBCT_dataset(dst_name='knee_zhao', random_views=True, num_views=10)
    item = dst[0]
    import pdb; pdb.set_trace()


import numpy as np
from keras.datasets import mnist

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

train_images = train_images.reshape(train_images.shape[0], -1)  # (60000, 784)
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape(test_images.shape[0], -1)
test_images = test_images.astype('float32') / 255

# 将标签数据转为int32 并且形状为(60000,1)
train_labels = train_labels.astype(np.int32)
test_labels = test_labels.astype(np.int32)
train_labels = train_labels.reshape(-1, 1)
test_labels = test_labels.reshape(-1, 1) #(10000,1)

test_num = [0,0,0,0,0,0,0,0,0,0]
for n in range(0,10):
    test_num[n] = np.sum(test_labels == n)
print(test_num)
print(np.sum(test_num))


import math
import string as S
import sys
#import separator

print('''
                                                                 __
                                                                /  |
 _______   __    __  _____  ____    ______    ______    ______  $$ |  ______    ______   __    __
/       \ /  |  /  |/     \/    \  /      \  /      \  /      \ $$ | /      \  /      \ /  |  /  |
$$$$$$$  |$$ |  $$ |$$$$$$ $$$$  |/$$$$$$  |/$$$$$$  |/$$$$$$  |$$ |/$$$$$$  |/$$$$$$  |$$ |  $$ |
$$ |  $$ |$$ |  $$ |$$ | $$ | $$ |$$    $$ |$$ |  $$/ $$ |  $$ |$$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |
$$ |  $$ |$$ \__$$ |$$ | $$ | $$ |$$$$$$$$/ $$ |      $$ \__$$ |$$ |$$ \__$$ |$$ \__$$ |$$ \__$$ |
$$ |  $$ |$$    $$/ $$ | $$ | $$ |$$       |$$ |      $$    $$/ $$ |$$    $$/ $$    $$ |$$    $$ |
$$/   $$/  $$$$$$/  $$/  $$/  $$/  $$$$$$$/ $$/        $$$$$$/  $$/  $$$$$$/   $$$$$$$ | $$$$$$$ |
                                                                              /  \__$$ |/  \__$$ |
                                                                              $$    $$/ $$    $$/
                                                                               $$$$$$/   $$$$$$/

                                                                               by nikjust08
''',)

kort1 = ("а", "и", "с", "ъ")
kort2 = ("б", "й", "т", "ы")
kort3 = ("в", "к", "у", "ь")
kort4 = ("г", "л", "ф", "э")
kort5 = ("д", "м", "х", "ю")
kort6 = ("е", "н", "ц", "я")
kort7 = ("ё", "о", "ч")
kort8 = ("ж", "п", "ш")
kort9 = ("з", "р", "щ")
print ("Введите Год")
BDYear = input()
BDYear = int(BDYear )
print ("Введите Месяц")
BDMonth = input()
BDMonth = int(BDMonth )
lim = 12
if BDMonth > lim:
    lim = 12
    print("Неверное число, проверьте исходные данные")
    input()
    os.abort()
print ("Введите День")
BDDay = int(BDDay )

#testingBD = (BDDay , BDMonth , BDYear)
#print (testingBD )
lim = 22

if BDDay > lim:
    lim = 22
    BDDay = BDDay - lim

lim = 12
if BDMonth > lim:
    lim = 12
    print("Неверное число, проверьте исходные данные")
    input()
    os.abort()

#print (BDDay)
#print (BDMonth)

form0 = BDDay - BDMonth
form1 = BDYear - BDDay
form2 = BDYear - BDMonth
if form0 < 0:
    form0 = form0 - form0 - form0

print ("Введите Имя")
name = input()
print ("Введите Фамилию")
Surname = input()
print ("Введите Отчество")
Patronymic = input()

name = name.lower()
Surname = Surname.lower()
Patronymic = Patronymic.lower()

namespl = list(name)
surnamespl = list(Surname)
patronymicspl = list(Patronymic)
i = 0
while i < len(namespl):
    if namespl[i] in kort1:
        namespl[i] = "1"
    if namespl[i] in kort2:
        namespl[i] = "2"
    if namespl[i] in kort3:
        namespl[i] = "3"
    if namespl[i] in kort4:
        namespl[i] = "4"
    if namespl[i] in kort5:
        namespl[i] = "5"
    if namespl[i] in kort6:
        namespl[i] = "6"
    if namespl[i] in kort7:
        namespl[i] = "7"
    if namespl[i] in kort8:
        namespl[i] = "8"
    if namespl[i] in kort9:
        namespl[i] = "9"

    i = i+1
il = 0
while il < len(surnamespl):
    if surnamespl[il] in kort1:
        surnamespl[il] = "1"
    if surnamespl[il] in kort2:
        surnamespl[il] = "2"
    if surnamespl[il] in kort3:
        surnamespl[il] = "3"
    if surnamespl[il] in kort4:
        surnamespl[il] = "4"
    if surnamespl[il] in kort5:
        surnamespl[il] = "5"
    if surnamespl[il] in kort6:
        surnamespl[il] = "6"
    if surnamespl[il] in kort7:
        surnamespl[il] = "7"
    if surnamespl[il] in kort8:
        surnamespl[il] = "8"
    if surnamespl[il] in kort9:
        surnamespl[il] = "9"

    il = il+1

im = 0
while im < len(patronymicspl):
    if patronymicspl[im] in kort1:
        patronymicspl[im] = "1"
    if patronymicspl[im] in kort2:
        patronymicspl[im] = "2"
    if patronymicspl[im] in kort3:
        patronymicspl[im] = "3"
    if patronymicspl[im] in kort4:
        patronymicspl[im] = "4"
    if patronymicspl[im] in kort5:
        patronymicspl[im] = "5"
    if patronymicspl[im] in kort6:
        patronymicspl[im] = "6"
    if patronymicspl[im] in kort7:
        patronymicspl[im] = "7"
    if patronymicspl[im] in kort8:
        patronymicspl[im] = "8"
    if patronymicspl[im] in kort9:
        patronymicspl[im] = "9"

    im = im+1

patronymicstr =  "".join(patronymicspl)
surnamestr = "".join(surnamespl)
namestr = "".join(namespl)
patronymicstr = int(patronymicstr)
surnamestr = int(surnamestr)
namestr = int(namestr)

allinone = int((namestr + surnamestr + patronymicstr) / 3)

BDBYear = str(BDYear)
fomaterYear = list(BDBYear)
i = 0
for i in range(0, len(fomaterYear)):
    fomaterYear[i] = int(fomaterYear[i])
sumofyear = sum(fomaterYear)

allinone = str(allinone)
namelist = list(allinone)
i = 0
for i in range(0, len(namelist)):
    namelist[i] = int(namelist[i])
namesum = sum(namelist)

i = 0
while 21 < namesum - 22:
    namesum - 22
form1 = sumofyear
if sumofyear > BDDay:
    form1 = sumofyear - BDDay

form2 = sumofyear
if sumofyear > BDMonth:
    form2 = sumofyear - BDMonth

print("ДР:", BDDay,".",BDMonth,".",sumofyear)
print("ОПВ:", form0)
print("ЗКУ:", form1)
print("ЭБ:", form2)
print("Число имени", namesum)

print("Нажмите enter Чтобы Продолжить")
input()

print("Выберите вид вычислений")
print("1.Деньги")
print("2.Здоровье")
print("3.Что-то еще")
while True:
    SelectorUse = input()

    if SelectorUse == "1":
        print(1)
        break
    elif SelectorUse == "2":
        print(2)
        break
    elif SelectorUse == "3":
        print(3)
        break
    else:
        print("Выберите вид вычислений")
        print("1.Деньги")
        print("2.Здоровье")
        print("3.Что-то еще")


import sys
sys.path.append('../')

from low_rank_rnns.modules import *
from low_rank_rnns import rdm, helpers, stats

size = 512
noise_std = 5e-2
alpha = .2
n_epochs_fr = 2
n_epochs = 2

x_train, y_train, mask_train, x_val, y_val, mask_val = rdm.generate_rdm_data(1000)
net = LowRankRNN(1, size, 1, noise_std, alpha, rank=1)
train(net, x_train, y_train, mask_train, n_epochs_fr, lr=1e-4, keep_best=True)
# torch.save(net.state_dict(), f'../models/rdm_rank1_{size}.pt')
net.load_state_dict(torch.load(f'../models/rdm_rank1_{size}.pt'))
rdm.test_rdm(net, x_val, y_val, mask_val)

output, traj = net.forward(x_train, return_dynamics=True)
n_trials = x_train.shape[0]
T = x_train.shape[1]
target = torch.tanh(traj[:, 1:].detach())

net2 = LowRankRNN(1, size, size, 0, alpha, rank=1, wo_init=size * torch.from_numpy(np.eye(size)), train_wi=True)
train(net2, x_train, target, torch.ones((n_trials, T, 1)), n_epochs, lr=1e-2, clip_gradient=1., keep_best=True, cuda=True)
net2 = net2.cpu()
# torch.save(net.state_dict(), f'../models/rdm_fitlr_{size}.pt')
out1, traj1 = net.forward(x_val, return_dynamics=True)
out2, traj2 = net2.forward(x_val, return_dynamics=True)
traj1 = net.non_linearity(traj1)
traj2 = net2.non_linearity(traj2)
y1 = traj1.detach().numpy().ravel()
y2 = traj2.detach().numpy().ravel()
r2 = stats.r2_score(y1, y2)
print(r2)


#
# @lc app=leetcode.cn id=1534 lang=python3
#
# [1534] 统计好三元组
#
# https://leetcode-cn.com/problems/count-good-triplets/description/
#
# algorithms
# Easy (78.21%)
# Likes:    5
# Dislikes: 0
# Total Accepted:    7.9K
# Total Submissions: 10K
# Testcase Example:  '[3,0,1,1,9,7]\n7\n2\n3'
#
# 给你一个整数数组 arr ，以及 a、b 、c 三个整数。请你统计其中好三元组的数量。
#
# 如果三元组 (arr[i], arr[j], arr[k]) 满足下列全部条件，则认为它是一个 好三元组 。
#
#
# 0 <= i < j < k < arr.length
# |arr[i] - arr[j]| <= a
# |arr[j] - arr[k]| <= b
# |arr[i] - arr[k]| <= c
#
#
# 其中 |x| 表示 x 的绝对值。
#
# 返回 好三元组的数量 。
#
#
#
# 示例 1：
#
# 输入：arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3
# 输出：4
# 解释：一共有 4 个好三元组：[(3,0,1), (3,0,1), (3,1,1), (0,1,1)] 。
#
#
# 示例 2：
#
# 输入：arr = [1,1,2,2,3], a = 0, b = 0, c = 1
# 输出：0
# 解释：不存在满足所有条件的三元组。
#
#
#
#
# 提示：
#
#
# 3 <= arr.length <= 100
# 0 <= arr[i] <= 1000
# 0 <= a, b, c <= 1000
#
#
#

from typing import List

# @lc code=start
class Solution:
    def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:
        res = 0
        for i in range(len(arr)):
            for j in range(i + 1, len(arr)):
                for k in range(j + 1, len(arr)):
                    if abs(arr[i] - arr[j]) <= a and \
                       abs(arr[j] - arr[k]) <= b and \
                       abs(arr[i] - arr[k]) <= c:
                        res += 1
        return res

# @lc code=end


t = int(input())
array = [int(input()) for _ in range(t)]

zero = [1, 0, 1]
one = [0, 1, 1]

def fibo(x):
    if len(zero) <= x:
        for j in range(len(zero), x+1):
            zero.append(zero[j-1]+zero[j-2])
            one.append(one[j-1]+one[j-2])

    return print(zero[x], one[x])

for i in array:
    fibo(i)


import json
from pprint import pprint
from src.environment import ReacherEnvironment
from src.mappo import MAPPO
from src.models import SimpleMAPPOAgent
import torch
import numpy as np
import datetime
import matplotlib.pyplot as plt

def train(*args, **kwargs):
    print(kwargs)

    device = 'cpu'
    kwargs['mappo']['device'] = device

    env = ReacherEnvironment(**kwargs['env'])
    env.reset(train_mode=True)

    state_dim = env.get_state_dim()
    action_dim = env.get_action_dim()
    kwargs['agent']['state_dim'] = state_dim
    kwargs['agent']['action_dim'] = action_dim
    kwargs['agent']['num_agents'] = env.get_num_agents()

    agent = SimpleMAPPOAgent(**kwargs['agent']).to(device)
    alg = MAPPO(agent=agent, **kwargs['mappo'])
    scores = alg.train(env, 5000)

    dt = str(datetime.datetime.now().strftime("%m_%d_%Y_%I_%M_%p"))
    model_fname = "../models/mappo_tennis_{}.pt".format(dt)
    torch.save(agent, model_fname)

    scores_fname = "../reports/mappo_tennis_{}".format(dt)
    np.save(scores_fname, np.asarray(scores))

    plt.plot(scores)
    plt.plot(np.convolve(scores, np.ones(100)/100)[:-100])
    fig_name = "../reports/mappo_tennis_{}.png".format(dt)
    plt.savefig(fig_name)

if __name__ == '__main__':
    with open('../config.json') as data_file:
        kwargs = json.load(data_file)
    pprint(kwargs)
    train(**kwargs)


input = [
    "forward 5",
    "down 5",
    "forward 8",
    "up 3",
    "down 8",
    "forward 2",
]

def part_one():
    with open('input.txt', 'r') as input_file:
        all_fish = input_file.readlines()

    all_fish = [3, 4, 3, 1, 2]

    for i in range(1, 18):
        new_fish = []
        for fish_age in all_fish:
            if fish_age == 0:
                new_fish.append(8)
            else:
                fish_age -= 1
        all_fish.append(new_fish)
        print(all_fish)

    print(len(all_fish))

def part_two():
    with open('input.txt', 'r') as input_file:
        lines = input_file.readlines()

if __name__ == "__main__":
    part_one()


s = input()

number = list(map(int, list(s.replace('+', ' ').replace('-', ' ').split())))
op = []

for i in list(s):
    if i == '+' or i  == '-':
        op.append(i)

result = number[0]
step = 0
check = False

for i in range(len(number) - 1):
    if op[i] == '-' and not check:
        check = True
        step += number[i+1]

    elif op[i] == '+' and not check:
        result += number[i + 1]

    elif op[i] == '+' and check:
        step += number[i + 1]

    elif op[i] == '-' and check:
        result -= step
        step = number[i + 1]

print(result - step)

SSAFY 대비 스터디/SSAFY 코테대비(Pycham)/test/1541.py