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

# -- GongChen'xi
#
#   20220112

# In[1]:

import baostock as bs
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import os, sys

# In[2]:

def fetch_info(stock_num, info, start_date, end_date):
    bs.login()
    rs = bs.query_history_k_data_plus(stock_num, info,
        start_date = start_date, end_date = end_date,
        frequency="d", adjustflag="3")
    data_list = []
    while (rs.error_code == '0') & rs.next():
        data_list.append(rs.get_row_data())
    bs.logout()
    return data_list

# In[3]:

# make dictionary of RSI6, RSI24
def get_rsi(stock_num, start_date, end_date):
    rsi6 = {}
    rsi24 = {}
    change = fetch_info(stock_num, 'date, pctChg', start_date, end_date)

    for i in range(len(change)):
        if i >= 23:
            date = change[i][0]

            # RSI6
            try:
                denominator = 0
                numerator = 0
                for j in range(6):
                    denominator += abs(float(change[i-j][1]))
                    if float(change[i-j][1]) > 0:
                        numerator += abs(float(change[i-j][1]))
                rsi6[date] = numerator/denominator
            except:
                rsi6[date] = 0.0

            # RSI24
            try:
                denominator = 0
                numerator = 0
                for j in range(24):
                    denominator += abs(float(change[i-j][1]))
                    if float(change[i-j][1]) > 0:
                        numerator += abs(float(change[i-j][1]))
                rsi24[date] = numerator/denominator
            except:
                rsi24[date] = 0.0
    return rsi6, rsi24

# In[4]:

# make dictionary of close price
def get_price(stock_num, start_date, end_date):
    close_price = {}
    close = fetch_info(stock_num, 'date, close', start_date, end_date)
    for i in range(len(close)):
        close_price[close[i][0]] = float(close[i][1])
    return close_price

# In[5]:

# make list of trading dates
def get_trading_dates(stock_num, start_date, end_date):
    trading_date_list = []
    date = fetch_info(stock_num, 'date', start_date, end_date)
    for i in range(len(date)):
        trading_date_list.append(date[i][0])
    return trading_date_list

# In[6]:

def change_rate(buy_date, date, close_price):
    buy_price = close_price[buy_date]
    current_price = close_price[date]
    change = (current_price-buy_price)/buy_price
    return change

def simulation_start_date(trading_date_list):
    date = trading_date_list[23]
    return date

def next_date(date, trading_date_list):
    new_date = None
    for i in range(len(trading_date_list)):
        if trading_date_list[i] == date:
            new_date = trading_date_list[i+1]
    return new_date

# In[ ]:

def initialize(stock_num, start_date, end_date):
    close_price = get_price(stock_num, start_date, end_date)
    trading_date_list = get_trading_dates(stock_num, start_date, end_date)
    date = simulation_start_date(trading_date_list)
    return close_price, trading_date_list, date

# In[ ]:

# analysis
def analysis(record, close_price, show):
    close = []
    date = []
    for i in close_price:
        close.append(close_price[i])
        date.append(i)
    t = []
    for i in range(len(close)):
        t.append(i)

    buy_price = []
    buy_t = []
    sell_price = []
    sell_t = []
    for i in record:
        for j in range(len(date)):
            if date[j] == i[0]:
                if i[1] == 'buy':
                    buy_price.append(close_price[date[j]])
                    buy_t.append(j)
                if i[1] == 'sell':
                    sell_price.append(close_price[date[j]])
                    sell_t.append(j)

    trade_list = []
    for i in record:
        for j in range(len(date)):
            if date[j] == i[0]:
                trade_list.append([i[0], i[1], close_price[date[j]]])
    trade = pd.DataFrame(trade_list, columns = ['date', 'action', 'close'])
    #print(trade, end = '\n\n')

    profit = []
    if len(trade_list) % 2 == 1:
        trade_list.pop()
    for i in range(int(len(trade_list)/2)):
        profit.append((trade_list[2*i+1][2] - trade_list[2*i][2])/trade_list[2*i][2])
    profit = np.array(profit)
    average = profit.mean()
    accumulated = ((profit + 1).cumprod() - 1)[-1]

    if show:
        print('On this pattern of trading,')
        print('Average yield: ', average)
        print('Accumulated yield: ', accumulated)
        plt.plot(t, close)
        plt.scatter(buy_t, buy_price, color = 'red')
        plt.scatter(sell_t, sell_price, color = 'green')

    return average, accumulated


# https://leetcode.com/problems/n-ary-tree-level-order-traversal/

from typing import List

# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children

class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        rst = []
        if not root:
            return rst

        curNodes = [root]
        while curNodes:
            nextNodes = []
            curVals = []
            for node in curNodes:
                curVals.append(node.val)
                if node.children:
                    nextNodes += node.children
            rst.append(curVals)
            curNodes = nextNodes
        return rst


import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

def get_data_splits(X, Y, train_size=0.8):
    """This function splits the whole dataset into train, test and validation sets.

    Args:
        X (pd.DataFrame): DataFrame containing feature values of data points of shape (num_samples,num_features)
        Y (pd.DataFrame): DataFrame containing labels for samples of shape (num_samples,)
        train_size (float, optional): size of the training set in (0,1), Defaults to 0.8.

    Returns:
        tuple: tuple containing X_train, Y_train, X_val, Y_val, X_test, Y_test
    """
    X_train, X_, Y_train, Y_ = train_test_split(X, Y, train_size=train_size, stratify=Y)
    X_val, X_test, Y_val, Y_test = train_test_split(X_, Y_, train_size=0.5, stratify=Y_)
    return X_train, Y_train, X_val, Y_val, X_test, Y_test

def rename_columns(df):
    """This function renames the columns of features DataFrame into cat_ and num_ styles.

    Args:
        df (pd.DataFrame): A DataFrame containing features as columns and samples as rows

    Returns:
        pd.DataFrame: A DataFrame with renamed columns.
    """
    categorical_cols = ["0", "1", "2", "3", "13"]
    numerical_cols = ["4", "5", "6", "7", "8", "9", "10", "11", "12"]
    new_names = []
    for col_name in df.columns.astype(str).values:
        if col_name in numerical_cols:
            df[col_name] = pd.to_numeric(df[col_name])
            new_names.append((col_name, "num_" + col_name))
        elif col_name in categorical_cols:
            new_names.append((col_name, "cat_" + col_name))
        else:  # pragma: no cover, other data
            new_names.append((col_name, col_name))
    df.rename(columns=dict(new_names), inplace=True)
    return df

def preprocess(X_df, Y_df=None, label_col="18", enc=None):
    """This function preprocess the features and labels DataFrames by encoding categorical features and relabeling. If Y_df is not None, normal samples get label 1 and anomalies get label -1.

    Args:
        X_df (pd.DataFrame): DataFrame containing features with renamed columns.
        Y_df (pd.DataFrame, optional): DataFrame containing the labels for samples in X_df. Defaults to None.
        label_col (str, optional): Name of the label column in Y_df. Defaults to "18".
        enc (sklearn.preprocessing.OneHotEncoder, optional): Fitted OneHotEncoder, a new encoder will be fit to the data if none is given. Defaults to None.

    Returns:
        tuple: df_new, Y_df, enc, the encoded features, the labels, and the OneHotEncoder
    """
    X_df = X_df.reset_index(drop=True)
    if Y_df is not None:
        Y_df = Y_df.reset_index(drop=True)
    if not enc:
        enc = OneHotEncoder(handle_unknown="ignore")
        enc.fit(X_df.loc[:, ["cat_" in i for i in X_df.columns]])
    num_cat_features = enc.transform(X_df.loc[:, ["cat_" in i for i in X_df.columns]]).toarray()
    df_catnum = pd.DataFrame(num_cat_features)
    df_catnum = df_catnum.add_prefix("catnum_")
    df_new = pd.concat([X_df, df_catnum], axis=1)
    if Y_df is not None:
        filter_clear = Y_df[label_col] == 1
        filter_infected = Y_df[label_col] < 0
        Y_df[label_col][filter_clear] = 1
        Y_df[label_col][filter_infected] = -1
    return df_new, Y_df, enc

def get_preprocessed_train(X_df, Y_df, label_col="18"):
    """This function prepares the dataset for training. Returns only normal samples.

    Args:
        X_df (pd.DataFrame): A DataFrame containing features for samples of shape (num_samples, num_features)
        Y_df (pd.DataFrame): A DataFrame containing labels for data samples of shape (n_samples,)
        label_col (str, optional): Name of the label column in Y_df. Defaults to "18"

    Returns:
        tuple: X_train_num, Y_train_clear, numerical_cols, ohe_enc: features and labels of normal samples together with names of the columns for training and the OneHotEncoder used in preprocessing
    """
    count_norm = X_df[Y_df[label_col] == 1].shape[0]
    count_anomaly = X_df[Y_df[label_col] != 1].shape[0]
    print("normal:", count_norm, "anomalies:", count_anomaly)
    X_df = rename_columns(X_df)
    X_df, Y_df, ohe_enc = preprocess(X_df, Y_df)
    # select numerical features
    numerical_cols = X_df.columns.to_numpy()[["num_" in i for i in X_df.columns]]
    X_train_clear = X_df[Y_df[label_col] == 1]
    Y_train_clear = Y_df[Y_df[label_col] == 1]
    X_train_num = X_train_clear[numerical_cols]
    return X_train_num, Y_train_clear, numerical_cols, ohe_enc

def get_test(X_df, enc, Y_df=None):
    """This function works similar to get_preprocessed_train, but prepares the test dataset for evaluation or inference purposes.

    Args:
        (pd.DataFrame): A DataFrame containing features for samples of shape (num_samples, num_features)
        enc (sklearn.preprocessing.OneHotEncoder): A fitted OneHotEncoder for transforming features
        Y_df (pd.DataFrame, optional): A DataFrame containing labels for data samples of shape (n_samples,), is none for inference purposes. Defaults to None.

    Returns:
        tuple: X_df, Y_df, preprocessed features and labels
    """
    X_df = rename_columns(X_df)
    X_df, Y_df, _ = preprocess(X_df, Y_df, enc=enc)
    numerical_cols = X_df.columns.to_numpy()[["num_" in i for i in X_df.columns]]
    X_df = X_df[numerical_cols]
    return X_df, Y_df


# -*- coding: utf-8 -*-

from django.conf.urls import url
from .views import HomeView, ArchivesView, AboutView, PhotoView, MusicView, ArticleDetailView, CategoryView, TagListView, TagsView, CategoryListView, search

urlpatterns = [
    url(r'^$', HomeView.as_view(), name='home'),
    url(r'^archives/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/$', ArchivesView.as_view(), name='archives'),

    url(r'^category_list/$', CategoryListView.as_view(), name='category_list'),    #分类列表页
    url(r'^category/(?P<category_id>\d+)/$', CategoryView.as_view(), name='category'),

    url(r'^tag_list/$', TagListView.as_view(), name='tag_list'),    #标签列表页
    url(r'^tag/(?P<tag_id>\d+)/$', TagsView.as_view(), name='tag'), #所属标签的文章列表

    url(r'^about/', AboutView.as_view(), name='about'),
    url(r'^photo/', PhotoView.as_view(), name='photo'),
    url(r'^music/', MusicView.as_view(), name='music'),
    url(r'^article_detail/(?P<article_id>\d+)/$', ArticleDetailView.as_view(), name='article_detail'),

    url(r'^search/$',search, name="search"),
]


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Aug 23 17:32:15 2020

geometry based sieving
"""

import os
import pickle

from skimage import measure
import pandas as pd
import numpy as np
import nibabel as nib
from skimage import measure
from sklearn import neighbors

# PROPERTIES = ['area', 'extent', 'filled_area', 'inertia_tensor', 'major_axis_length', 'minor_axis_length'] # 3d compatible
PROPERTIES = ['area', 'eccentricity', 'extent',
              'inertia_tensor', 'major_axis_length', 'minor_axis_length',
              'moments_hu', 'perimeter', 'solidity']
def read_nifti(img_path):
    """
    Wrapper for nibabel to read in NIfTI scans.

    Parameters
    ----------
    img_path : string
        The path to the .nii scan

    Returns
    -------
    A numpy array representing the scan

    """
    raw = nib.load(img_path)
    img = raw.get_fdata()

    return img

def label_2d(im):
    labeled = im.copy()
    vals_seen = []
    adder = 0
    for i in range(labeled.shape[2]):
        sli = im[:,:,i]
        labeled_slice = measure.label(sli)
        labeled_slice = labeled_slice + (adder * (~np.isclose(labeled_slice, 0)))# we are labeling every slice individually, but we don't want to reuse labels between slices
        labeled[:,:,i] = labeled_slice
        the_max = labeled_slice.max()
        if the_max > 0:
            adder = the_max

        vals_seen.extend(np.unique(labeled_slice))
        vals_seen.remove(0)
        '''
        print(f'Vals_seen: {vals_seen}')
        print(f'Adder: {adder}')
        print(f'Unique in this slice: {np.unique(labeled_slice)}')
        print('\n')
        '''
        if len(vals_seen) > len(np.unique(vals_seen)):
            raise Exception(f'Labels are not unique after slice {i}')

    return labeled.astype(int)

def generate_properties(im, props=PROPERTIES):
    """
    Generates geometric properties for shapes in the binary input image

    Parameters
    ----------
    im : TYPE
        DESCRIPTION.
    props : TYPE, optional
        DESCRIPTION

    Returns
    -------
    X_train : TYPE
        DESCRIPTION.

    """
    X_train = pd.DataFrame()

    labeled = label_2d(im)
    for i in range(labeled.shape[2]):
        sli = labeled[:,:,i]
        try:
            X_train = X_train.append(pd.DataFrame(measure.regionprops_table(sli, properties=props)))
        except IndexError:
            pass # happens when the slice has no regions in it

    return X_train

def standardize_data(data, params):

    standard_data = data.copy()

    for col, mean, stddev in zip(data.columns, params[0], params[1]):
        standard_data[col] = (standard_data[col] - mean) / stddev

    return standard_data

def train_and_save(training_data, outloc):
    """
    Trains a LOF algorithm for the purposes of novelty detection and pickles it
    Standardizes the data first (transforms each column by subtracting the mean
    and then dividing by the stddev)

    Parameters
    ----------
    training_data : TYPE
        a pandas DataFrame of the training data.
    out_loc : TYPE
        name of the pickled object to save, which is a tuple with length 2, where
        the first entry is the model. The second is a list of lists, where the first
        list is the list of means used to transform the data and the second is the list
        of the stddevs used to transform the data

    Returns
    -------
     a tuple with length 2, where
        the first entry is the model. The second is a list of lists, where the first
        list is the list of means used to transform the data and the second is the list
        of the stddevs used to transform the data

    """
    standard_data = training_data.copy()

    means = []
    stddevs = []
    for col in training_data.columns:
        mean = training_data[col].mean()
        stddev = training_data[col].std()

        means.append(mean)
        stddevs.append(stddev)

    standard_data = standardize_data(training_data, (means, stddevs))

    lof = neighbors.LocalOutlierFactor(novelty=True)
    lof.fit(standard_data)

    out_obj = (lof, (means, stddevs))
    pickle.dump(out_obj, open(outloc, "wb" ))

    return out_obj

def load_default_model():
    script_folder = os.path.dirname(os.path.realpath(__file__))
    repo_folder = os.path.dirname(script_folder)
    model_loc = os.path.join(repo_folder, 'bin', 'gbs_models', 'gbs_default.pkl')

    lof, params = pickle.load(open(model_loc, 'rb'))

    return lof, params

def sieve_image(im, model_and_params=None, props=None):

    if model_and_params is None:
        model_and_params = load_default_model()
    if props is None:
        props=PROPERTIES

    model = model_and_params[0]
    params = model_and_params[1]

    labeled = label_2d(im)
    #observations = pd.DataFrame(measure.regionprops_table(labeled, properties=props))

    props_with_label = props
    props_with_label.append('label')

    observations = generate_properties(labeled, props=props_with_label)
    labels_only = pd.DataFrame(observations['label'])
    observations_drop = observations.drop(columns='label')

    standard_observations = standardize_data(observations_drop, params)

    predictions = model.predict(standard_observations)
    labels_only['prediction'] = predictions

    to_zero = [row['label'] for i, row in labels_only.iterrows() if row['prediction'] == -1]

    mask = np.isin(labeled, to_zero)

    new_im = im.copy()
    new_im[mask] = 0

    return new_im.astype(int)


import os
import torch
import pandas as pd
import torchaudio
import cv2
import torchaudio.transforms as T
from torch.utils.data import Dataset
import numpy as np

from .utils_dataset import get_transform

class BatvisionV2Dataset(Dataset):

    def __init__(self, cfg, annotation_file, location_blacklist=None):

        self.cfg = cfg
        self.root_dir = cfg.dataset.dataset_dir
        self.audio_format = cfg.dataset.audio_format

        location_list = os.listdir(self.root_dir)
        if location_blacklist:
            location_list = [location for location in location_list if location not in location_blacklist]
        location_csv_paths = [os.path.join(self.root_dir, location, annotation_file) for location in location_list]

        self.instances = []

        for location_csv in location_csv_paths:
            self.instances.append(pd.read_csv(location_csv))

        self.instances = pd.concat(self.instances)

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

    def __getitem__(self, idx):
        # Access instance
        instance = self.instances.iloc[idx]

        # Load path
        depth_path = os.path.join(self.root_dir,instance['depth path'],instance['depth file name'])
        audio_path = os.path.join(self.root_dir,instance['audio path'],instance['audio file name'])

        ## Depth
        # Load depth map
        depth = np.load(depth_path).astype(np.float32)
        depth = depth / 1000 # to go from mm to m
        if self.cfg.dataset.max_depth:
            depth[depth > self.cfg.dataset.max_depth] = self.cfg.dataset.max_depth
        # Transform
        depth_transform = get_transform(self.cfg, convert =  True, depth_norm = self.cfg.dataset.depth_norm)
        gt_depth = depth_transform(depth)

        ## Audio
        # Load audio binaural waveform
        waveform, sr = torchaudio.load(audio_path)
        # STFT parameters for full length audio
        win_length = 200
        n_fft = 400
        hop_length = 100

        # Cut audio to fit max depth
        if self.cfg.dataset.max_depth:
            cut = int((2*self.cfg.dataset.max_depth / 340) * sr)
            waveform = waveform[:,:cut]
            # Update STFT parameters
            win_length = 64
            n_fft = 512
            hop_length=64//4

        # Process sound
        if 'spectrogram' in self.audio_format:
            if 'mel' in self.audio_format:
                spec = self._get_melspectrogram(waveform, n_fft = n_fft, power = 1.0, win_length = win_length)
            else:
                spec = self._get_spectrogram(waveform, n_fft = n_fft, power = 1.0, win_length = win_length, hop_length =  hop_length)
            spec_transform =  get_transform(self.cfg, convert = False) # convert False because already a tensor
            audio2return = spec_transform(spec)
        elif 'waveform' in self.audio_format:
            audio2return = waveform

        return audio2return, gt_depth

    # audio transformation: spectrogram
    def _get_spectrogram(self, waveform, n_fft = 400, power = 1.0, win_length = 400, hop_length=100):

        spectrogram = T.Spectrogram(
          n_fft=n_fft,
          win_length=win_length,
          power=power,
          hop_length=hop_length,
        )
        #db = T.AmplitudeToDB(stype = 'magnitude')
        return spectrogram(waveform)

    # audio transformation: mel spectrogram
    def _get_melspectrogram(self, waveform, n_fft = 400, power = 1.0, win_length = 400, f_min = 20.0, f_max = 20000.0):

        melspectrogram = T.MelSpectrogram(sample_rate = 44100,
          n_fft=n_fft,
          win_length=win_length,
          power=power,
          f_min = f_min,
          f_max = f_max,
          n_mels = 32,
        )
        return melspectrogram(waveform)


"""
Python Crash Course, Third Edition https://ehmatthes.github.io/pcc_3e/
My notes: https://github.com/egalli64/pythonesque/pcc3

Chapter 15 - Generating Data - Plotting a Simple Line Graph - Plotting a Series of Points with scatter()
"""
import matplotlib.pyplot as plt

plt.style.use('seaborn')
fig, ax = plt.subplots()

# a few scattered points
xs = [1, 2, 3, 4, 5]
ys = [1, 4, 9, 16, 25]
ax.scatter(xs, ys, s=100)

ax.set_title("Square Numbers", fontsize=24)
ax.set_xlabel("Value", fontsize=14)
ax.set_ylabel("Square of Value", fontsize=14)
ax.tick_params(labelsize=14)

plt.show()


import dataclasses
import pickle
import re
from collections.abc import Hashable
from datetime import datetime
from pathlib import Path
from typing import Callable, ClassVar, Dict, FrozenSet, List, Optional, Set, Union

import pytest
from typing_extensions import Literal

import pydantic
from pydantic import BaseModel, Extra, ValidationError, validator

def test_simple():
    @pydantic.dataclasses.dataclass
    class MyDataclass:
        a: int
        b: float

    d = MyDataclass('1', '2.5')
    assert d.a == 1
    assert d.b == 2.5
    d = MyDataclass(b=10, a=20)
    assert d.a == 20
    assert d.b == 10

def test_model_name():
    @pydantic.dataclasses.dataclass
    class MyDataClass:
        model_name: str

    d = MyDataClass('foo')
    assert d.model_name == 'foo'
    d = MyDataClass(model_name='foo')
    assert d.model_name == 'foo'

def test_value_error():
    @pydantic.dataclasses.dataclass
    class MyDataclass:
        a: int
        b: int

    with pytest.raises(ValidationError) as exc_info:
        MyDataclass(1, 'wrong')

    assert exc_info.value.errors() == [
        {'loc': ('b',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
    ]

def test_frozen():
    @pydantic.dataclasses.dataclass(frozen=True)
    class MyDataclass:
        a: int

    d = MyDataclass(1)
    assert d.a == 1

    with pytest.raises(AttributeError):
        d.a = 7

def test_validate_assignment():
    class Config:
        validate_assignment = True

    @pydantic.dataclasses.dataclass(config=Config)
    class MyDataclass:
        a: int

    d = MyDataclass(1)
    assert d.a == 1

    d.a = '7'
    assert d.a == 7

def test_validate_assignment_error():
    @pydantic.dataclasses.dataclass(config=dict(validate_assignment=True))
    class MyDataclass:
        a: int

    d = MyDataclass(1)

    with pytest.raises(ValidationError) as exc_info:
        d.a = 'xxx'
    assert exc_info.value.errors() == [
        {'loc': ('a',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
    ]

def test_not_validate_assignment():
    @pydantic.dataclasses.dataclass
    class MyDataclass:
        a: int

    d = MyDataclass(1)
    assert d.a == 1

    d.a = '7'
    assert d.a == '7'

def test_validate_assignment_value_change():
    class Config:
        validate_assignment = True

    @pydantic.dataclasses.dataclass(config=Config, frozen=False)
    class MyDataclass:
        a: int

        @validator('a')
        def double_a(cls, v):
            return v * 2

    d = MyDataclass(2)
    assert d.a == 4

    d.a = 3
    assert d.a == 6

def test_validate_assignment_extra():
    class Config:
        validate_assignment = True

    @pydantic.dataclasses.dataclass(config=Config, frozen=False)
    class MyDataclass:
        a: int

    d = MyDataclass(1)
    assert d.a == 1

    d.extra_field = 1.23
    assert d.extra_field == 1.23
    d.extra_field = 'bye'
    assert d.extra_field == 'bye'

def test_post_init():
    post_init_called = False

    @pydantic.dataclasses.dataclass
    class MyDataclass:
        a: int

        def __post_init__(self):
            nonlocal post_init_called
            post_init_called = True

    d = MyDataclass('1')
    assert d.a == 1
    assert post_init_called

def test_post_init_validation():
    @dataclasses.dataclass
    class DC:
        a: int

        def __post_init__(self):
            self.a *= 2

        def __post_init_post_parse__(self):
            self.a += 1

    PydanticDC = pydantic.dataclasses.dataclass(DC)
    assert DC(a='2').a == '22'
    assert PydanticDC(a='2').a == 23

def test_post_init_inheritance_chain():
    parent_post_init_called = False
    post_init_called = False

    @pydantic.dataclasses.dataclass
    class ParentDataclass:
        a: int

        def __post_init__(self):
            nonlocal parent_post_init_called
            parent_post_init_called = True

    @pydantic.dataclasses.dataclass
    class MyDataclass(ParentDataclass):
        b: int

        def __post_init__(self):
            super().__post_init__()
            nonlocal post_init_called
            post_init_called = True

    d = MyDataclass(a=1, b=2)
    assert d.a == 1
    assert d.b == 2
    assert parent_post_init_called
    assert post_init_called

def test_post_init_post_parse():
    post_init_post_parse_called = False

    @pydantic.dataclasses.dataclass
    class MyDataclass:
        a: int

        def __post_init_post_parse__(self):
            nonlocal post_init_post_parse_called
            post_init_post_parse_called = True

    d = MyDataclass('1')
    assert d.a == 1
    assert post_init_post_parse_called

def test_post_init_post_parse_types():
    @pydantic.dataclasses.dataclass
    class CustomType:
        b: int

    @pydantic.dataclasses.dataclass
    class MyDataclass:
        a: CustomType

        def __post_init__(self):
            assert type(self.a) == dict

        def __post_init_post_parse__(self):
            assert type(self.a) == CustomType

    d = MyDataclass(**{'a': {'b': 1}})
    assert d.a.b == 1

def test_post_init_assignment():
    from dataclasses import field

    # Based on: https://docs.python.org/3/library/dataclasses.html#post-init-processing
    @pydantic.dataclasses.dataclass
    class C:
        a: float
        b: float
        c: float = field(init=False)

        def __post_init__(self):
            self.c = self.a + self.b

    c = C(0.1, 0.2)
    assert c.a == 0.1
    assert c.b == 0.2
    assert c.c == 0.30000000000000004

def test_inheritance():
    @pydantic.dataclasses.dataclass
    class A:
        a: str = None

    @pydantic.dataclasses.dataclass
    class B(A):
        b: int = None

    b = B(a='a', b=12)
    assert b.a == 'a'
    assert b.b == 12

    with pytest.raises(ValidationError):
        B(a='a', b='b')

def test_validate_long_string_error():
    class Config:
        max_anystr_length = 3

    @pydantic.dataclasses.dataclass(config=Config)
    class MyDataclass:
        a: str

    with pytest.raises(ValidationError) as exc_info:
        MyDataclass('xxxx')

    assert exc_info.value.errors() == [
        {
            'loc': ('a',),
            'msg': 'ensure this value has at most 3 characters',
            'type': 'value_error.any_str.max_length',
            'ctx': {'limit_value': 3},
        }
    ]

def test_validate_assigment_long_string_error():
    class Config:
        max_anystr_length = 3
        validate_assignment = True

    @pydantic.dataclasses.dataclass(config=Config)
    class MyDataclass:
        a: str

    d = MyDataclass('xxx')
    with pytest.raises(ValidationError) as exc_info:
        d.a = 'xxxx'

    assert issubclass(MyDataclass.__pydantic_model__.__config__, BaseModel.Config)
    assert exc_info.value.errors() == [
        {
            'loc': ('a',),
            'msg': 'ensure this value has at most 3 characters',
            'type': 'value_error.any_str.max_length',
            'ctx': {'limit_value': 3},
        }
    ]

def test_no_validate_assigment_long_string_error():
    class Config:
        max_anystr_length = 3
        validate_assignment = False

    @pydantic.dataclasses.dataclass(config=Config)
    class MyDataclass:
        a: str

    d = MyDataclass('xxx')
    d.a = 'xxxx'

    assert d.a == 'xxxx'

def test_nested_dataclass():
    @pydantic.dataclasses.dataclass
    class Nested:
        number: int

    @pydantic.dataclasses.dataclass
    class Outer:
        n: Nested

    navbar = Outer(n=Nested(number='1'))
    assert isinstance(navbar.n, Nested)
    assert navbar.n.number == 1

    navbar = Outer(n=('2',))
    assert isinstance(navbar.n, Nested)
    assert navbar.n.number == 2

    navbar = Outer(n={'number': '3'})
    assert isinstance(navbar.n, Nested)
    assert navbar.n.number == 3

    with pytest.raises(ValidationError) as exc_info:
        Outer(n='not nested')
    assert exc_info.value.errors() == [
        {
            'loc': ('n',),
            'msg': 'instance of Nested, tuple or dict expected',
            'type': 'type_error.dataclass',
            'ctx': {'class_name': 'Nested'},
        }
    ]

    with pytest.raises(ValidationError) as exc_info:
        Outer(n=('x',))
    assert exc_info.value.errors() == [
        {'loc': ('n', 'number'), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
    ]

def test_arbitrary_types_allowed():
    class Button:
        def __init__(self, href: str):
            self.href = href

    class Config:
        arbitrary_types_allowed = True

    @pydantic.dataclasses.dataclass(config=Config)
    class Navbar:
        button: Button

    btn = Button(href='a')
    navbar = Navbar(button=btn)
    assert navbar.button.href == 'a'

    with pytest.raises(ValidationError) as exc_info:
        Navbar(button=('b',))
    assert exc_info.value.errors() == [
        {
            'loc': ('button',),
            'msg': 'instance of Button expected',
            'type': 'type_error.arbitrary_type',
            'ctx': {'expected_arbitrary_type': 'Button'},
        }
    ]

def test_nested_dataclass_model():
    @pydantic.dataclasses.dataclass
    class Nested:
        number: int

    class Outer(BaseModel):
        n: Nested

    navbar = Outer(n=Nested(number='1'))
    assert navbar.n.number == 1

def test_fields():
    @pydantic.dataclasses.dataclass
    class User:
        id: int
        name: str = 'John Doe'
        signup_ts: datetime = None

    user = User(id=123)
    fields = user.__pydantic_model__.__fields__

    assert fields['id'].required is True
    assert fields['id'].default is None

    assert fields['name'].required is False
    assert fields['name'].default == 'John Doe'

    assert fields['signup_ts'].required is False
    assert fields['signup_ts'].default is None

def test_default_factory_field():
    @pydantic.dataclasses.dataclass
    class User:
        id: int
        aliases: Dict[str, str] = dataclasses.field(default_factory=lambda: {'John': 'Joey'})

    user = User(id=123)
    fields = user.__pydantic_model__.__fields__

    assert fields['id'].required is True
    assert fields['id'].default is None

    assert fields['aliases'].required is False
    assert fields['aliases'].default_factory() == {'John': 'Joey'}

def test_default_factory_singleton_field():
    class MySingleton:
        pass

    class MyConfig:
        arbitrary_types_allowed = True

    MY_SINGLETON = MySingleton()

    @pydantic.dataclasses.dataclass(config=MyConfig)
    class Foo:
        singleton: MySingleton = dataclasses.field(default_factory=lambda: MY_SINGLETON)

    # Returning a singleton from a default_factory is supported
    assert Foo().singleton is Foo().singleton

def test_schema():
    @pydantic.dataclasses.dataclass
    class User:
        id: int
        name: str = 'John Doe'
        aliases: Dict[str, str] = dataclasses.field(default_factory=lambda: {'John': 'Joey'})
        signup_ts: datetime = None
        age: Optional[int] = dataclasses.field(
            default=None, metadata=dict(title='The age of the user', description='do not lie!')
        )
        height: Optional[int] = pydantic.Field(None, title='The height in cm', ge=50, le=300)

    user = User(id=123)
    assert user.__pydantic_model__.schema() == {
        'title': 'User',
        'type': 'object',
        'properties': {
            'id': {'title': 'Id', 'type': 'integer'},
            'name': {'title': 'Name', 'default': 'John Doe', 'type': 'string'},
            'aliases': {
                'title': 'Aliases',
                'type': 'object',
                'additionalProperties': {'type': 'string'},
            },
            'signup_ts': {'title': 'Signup Ts', 'type': 'string', 'format': 'date-time'},
            'age': {
                'title': 'The age of the user',
                'description': 'do not lie!',
                'type': 'integer',
            },
            'height': {
                'title': 'The height in cm',
                'minimum': 50,
                'maximum': 300,
                'type': 'integer',
            },
        },
        'required': ['id'],
    }

def test_nested_schema():
    @pydantic.dataclasses.dataclass
    class Nested:
        number: int

    @pydantic.dataclasses.dataclass
    class Outer:
        n: Nested

    assert Outer.__pydantic_model__.schema() == {
        'title': 'Outer',
        'type': 'object',
        'properties': {'n': {'$ref': '#/definitions/Nested'}},
        'required': ['n'],
        'definitions': {
            'Nested': {
                'title': 'Nested',
                'type': 'object',
                'properties': {'number': {'title': 'Number', 'type': 'integer'}},
                'required': ['number'],
            }
        },
    }

def test_initvar():
    InitVar = dataclasses.InitVar

    @pydantic.dataclasses.dataclass
    class TestInitVar:
        x: int
        y: InitVar

    tiv = TestInitVar(1, 2)
    assert tiv.x == 1
    with pytest.raises(AttributeError):
        tiv.y

def test_derived_field_from_initvar():
    InitVar = dataclasses.InitVar

    @pydantic.dataclasses.dataclass
    class DerivedWithInitVar:
        plusone: int = dataclasses.field(init=False)
        number: InitVar[int]

        def __post_init__(self, number):
            self.plusone = number + 1

    derived = DerivedWithInitVar(1)
    assert derived.plusone == 2
    with pytest.raises(TypeError):
        DerivedWithInitVar('Not A Number')

def test_initvars_post_init():
    @pydantic.dataclasses.dataclass
    class PathDataPostInit:
        path: Path
        base_path: dataclasses.InitVar[Optional[Path]] = None

        def __post_init__(self, base_path):
            if base_path is not None:
                self.path = base_path / self.path

    path_data = PathDataPostInit('world')
    assert 'path' in path_data.__dict__
    assert 'base_path' not in path_data.__dict__
    assert path_data.path == Path('world')

    with pytest.raises(TypeError) as exc_info:
        PathDataPostInit('world', base_path='/hello')
    assert str(exc_info.value) == "unsupported operand type(s) for /: 'str' and 'str'"

def test_initvars_post_init_post_parse():
    @pydantic.dataclasses.dataclass
    class PathDataPostInitPostParse:
        path: Path
        base_path: dataclasses.InitVar[Optional[Path]] = None

        def __post_init_post_parse__(self, base_path):
            if base_path is not None:
                self.path = base_path / self.path

    path_data = PathDataPostInitPostParse('world')
    assert 'path' in path_data.__dict__
    assert 'base_path' not in path_data.__dict__
    assert path_data.path == Path('world')

    assert PathDataPostInitPostParse('world', base_path='/hello').path == Path('/hello/world')

def test_classvar():
    @pydantic.dataclasses.dataclass
    class TestClassVar:
        klassvar: ClassVar = "I'm a Class variable"
        x: int

    tcv = TestClassVar(2)
    assert tcv.klassvar == "I'm a Class variable"

def test_frozenset_field():
    @pydantic.dataclasses.dataclass
    class TestFrozenSet:
        set: FrozenSet[int]

    test_set = frozenset({1, 2, 3})
    object_under_test = TestFrozenSet(set=test_set)

    assert object_under_test.set == test_set

def test_inheritance_post_init():
    post_init_called = False

    @pydantic.dataclasses.dataclass
    class Base:
        a: int

        def __post_init__(self):
            nonlocal post_init_called
            post_init_called = True

    @pydantic.dataclasses.dataclass
    class Child(Base):
        b: int

    Child(a=1, b=2)
    assert post_init_called

def test_hashable_required():
    @pydantic.dataclasses.dataclass
    class MyDataclass:
        v: Hashable

    MyDataclass(v=None)
    with pytest.raises(ValidationError) as exc_info:
        MyDataclass(v=[])
    assert exc_info.value.errors() == [
        {'loc': ('v',), 'msg': 'value is not a valid hashable', 'type': 'type_error.hashable'}
    ]
    with pytest.raises(TypeError) as exc_info:
        MyDataclass()
    assert "__init__() missing 1 required positional argument: 'v'" in str(exc_info.value)

@pytest.mark.parametrize('default', [1, None, ...])
def test_hashable_optional(default):
    @pydantic.dataclasses.dataclass
    class MyDataclass:
        v: Hashable = default

    MyDataclass()
    MyDataclass(v=None)

def test_override_builtin_dataclass():
    @dataclasses.dataclass
    class File:
        hash: str
        name: Optional[str]
        size: int
        content: Optional[bytes] = None

    ValidFile = pydantic.dataclasses.dataclass(File)

    file = File(hash='xxx', name=b'whatever.txt', size='456')
    valid_file = ValidFile(hash='xxx', name=b'whatever.txt', size='456')

    assert file.name == b'whatever.txt'
    assert file.size == '456'

    assert valid_file.name == 'whatever.txt'
    assert valid_file.size == 456

    assert isinstance(valid_file, File)
    assert isinstance(valid_file, ValidFile)

    with pytest.raises(ValidationError) as e:
        ValidFile(hash=[1], name='name', size=3)
    assert e.value.errors() == [{'loc': ('hash',), 'msg': 'str type expected', 'type': 'type_error.str'}]

def test_override_builtin_dataclass_2():
    @dataclasses.dataclass
    class Meta:
        modified_date: Optional[datetime]
        seen_count: int

    Meta(modified_date='not-validated', seen_count=0)

    @pydantic.dataclasses.dataclass
    @dataclasses.dataclass
    class File(Meta):
        filename: str

    Meta(modified_date='still-not-validated', seen_count=0)

    f = File(filename=b'thefilename', modified_date='2020-01-01T00:00', seen_count='7')
    assert f.filename == 'thefilename'
    assert f.modified_date == datetime(2020, 1, 1, 0, 0)
    assert f.seen_count == 7

def test_override_builtin_dataclass_nested():
    @dataclasses.dataclass
    class Meta:
        modified_date: Optional[datetime]
        seen_count: int

    @dataclasses.dataclass
    class File:
        filename: str
        meta: Meta

    class Foo(BaseModel):
        file: File

    FileChecked = pydantic.dataclasses.dataclass(File)
    f = FileChecked(filename=b'thefilename', meta=Meta(modified_date='2020-01-01T00:00', seen_count='7'))
    assert f.filename == 'thefilename'
    assert f.meta.modified_date == datetime(2020, 1, 1, 0, 0)
    assert f.meta.seen_count == 7

    with pytest.raises(ValidationError) as e:
        FileChecked(filename=b'thefilename', meta=Meta(modified_date='2020-01-01T00:00', seen_count=['7']))
    assert e.value.errors() == [
        {'loc': ('meta', 'seen_count'), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
    ]

    foo = Foo.parse_obj(
        {
            'file': {
                'filename': b'thefilename',
                'meta': {'modified_date': '2020-01-01T00:00', 'seen_count': '7'},
            },
        }
    )
    assert foo.file.filename == 'thefilename'
    assert foo.file.meta.modified_date == datetime(2020, 1, 1, 0, 0)
    assert foo.file.meta.seen_count == 7

def test_override_builtin_dataclass_nested_schema():
    @dataclasses.dataclass
    class Meta:
        modified_date: Optional[datetime]
        seen_count: int

    @dataclasses.dataclass
    class File:
        filename: str
        meta: Meta

    FileChecked = pydantic.dataclasses.dataclass(File)
    assert FileChecked.__pydantic_model__.schema() == {
        'definitions': {
            'Meta': {
                'properties': {
                    'modified_date': {'format': 'date-time', 'title': 'Modified ' 'Date', 'type': 'string'},
                    'seen_count': {'title': 'Seen Count', 'type': 'integer'},
                },
                'required': ['modified_date', 'seen_count'],
                'title': 'Meta',
                'type': 'object',
            }
        },
        'properties': {
            'filename': {'title': 'Filename', 'type': 'string'},
            'meta': {'$ref': '#/definitions/Meta'},
        },
        'required': ['filename', 'meta'],
        'title': 'File',
        'type': 'object',
    }

def test_inherit_builtin_dataclass():
    @dataclasses.dataclass
    class Z:
        z: int

    @dataclasses.dataclass
    class Y(Z):
        y: int

    @pydantic.dataclasses.dataclass
    class X(Y):
        x: int

    pika = X(x='2', y='4', z='3')
    assert pika.x == 2
    assert pika.y == 4
    assert pika.z == 3

def test_dataclass_arbitrary():
    class ArbitraryType:
        def __init__(self):
            ...

    @dataclasses.dataclass
    class Test:
        foo: ArbitraryType
        bar: List[ArbitraryType]

    class TestModel(BaseModel):
        a: ArbitraryType
        b: Test

        class Config:
            arbitrary_types_allowed = True

    TestModel(a=ArbitraryType(), b=(ArbitraryType(), [ArbitraryType()]))

def test_forward_stdlib_dataclass_params():
    @dataclasses.dataclass(frozen=True)
    class Item:
        name: str

    class Example(BaseModel):
        item: Item
        other: str

        class Config:
            arbitrary_types_allowed = True

    e = Example(item=Item(name='pika'), other='bulbi')
    e.other = 'bulbi2'
    with pytest.raises(dataclasses.FrozenInstanceError):
        e.item.name = 'pika2'

def test_pydantic_callable_field():
    """pydantic callable fields behaviour should be the same as stdlib dataclass"""

    def foo(arg1, arg2):
        return arg1, arg2

    def bar(x: int, y: float, z: str) -> bool:
        return str(x + y) == z

    class PydanticModel(BaseModel):
        required_callable: Callable
        required_callable_2: Callable[[int, float, str], bool]

        default_callable: Callable = foo
        default_callable_2: Callable[[int, float, str], bool] = bar

    @pydantic.dataclasses.dataclass
    class PydanticDataclass:
        required_callable: Callable
        required_callable_2: Callable[[int, float, str], bool]

        default_callable: Callable = foo
        default_callable_2: Callable[[int, float, str], bool] = bar

    @dataclasses.dataclass
    class StdlibDataclass:
        required_callable: Callable
        required_callable_2: Callable[[int, float, str], bool]

        default_callable: Callable = foo
        default_callable_2: Callable[[int, float, str], bool] = bar

    pyd_m = PydanticModel(required_callable=foo, required_callable_2=bar)
    pyd_dc = PydanticDataclass(required_callable=foo, required_callable_2=bar)
    std_dc = StdlibDataclass(required_callable=foo, required_callable_2=bar)

    assert (
        pyd_m.required_callable
        is pyd_m.default_callable
        is pyd_dc.required_callable
        is pyd_dc.default_callable
        is std_dc.required_callable
        is std_dc.default_callable
    )
    assert (
        pyd_m.required_callable_2
        is pyd_m.default_callable_2
        is pyd_dc.required_callable_2
        is pyd_dc.default_callable_2
        is std_dc.required_callable_2
        is std_dc.default_callable_2
    )

def test_pickle_overriden_builtin_dataclass(create_module):
    module = create_module(
        # language=Python
        """\
import dataclasses
import pydantic

@dataclasses.dataclass
class BuiltInDataclassForPickle:
    value: int

class ModelForPickle(pydantic.BaseModel):
    # pickle can only work with top level classes as it imports them

    dataclass: BuiltInDataclassForPickle

    class Config:
        validate_assignment = True
        """
    )
    obj = module.ModelForPickle(dataclass=module.BuiltInDataclassForPickle(value=5))

    pickled_obj = pickle.dumps(obj)
    restored_obj = pickle.loads(pickled_obj)

    assert restored_obj.dataclass.value == 5
    assert restored_obj == obj

    # ensure the restored dataclass is still a pydantic dataclass
    with pytest.raises(ValidationError, match='value\n +value is not a valid integer'):
        restored_obj.dataclass.value = 'value of a wrong type'

def test_config_field_info_create_model():
    # works
    class A1(BaseModel):
        a: str

        class Config:
            fields = {'a': {'description': 'descr'}}

    assert A1.schema()['properties'] == {'a': {'title': 'A', 'description': 'descr', 'type': 'string'}}

    @pydantic.dataclasses.dataclass(config=A1.Config)
    class A2:
        a: str

    assert A2.__pydantic_model__.schema()['properties'] == {
        'a': {'title': 'A', 'description': 'descr', 'type': 'string'}
    }

def gen_2162_dataclasses():
    @dataclasses.dataclass(frozen=True)
    class StdLibFoo:
        a: str
        b: int

    @pydantic.dataclasses.dataclass(frozen=True)
    class PydanticFoo:
        a: str
        b: int

    @dataclasses.dataclass(frozen=True)
    class StdLibBar:
        c: StdLibFoo

    @pydantic.dataclasses.dataclass(frozen=True)
    class PydanticBar:
        c: PydanticFoo

    @dataclasses.dataclass(frozen=True)
    class StdLibBaz:
        c: PydanticFoo

    @pydantic.dataclasses.dataclass(frozen=True)
    class PydanticBaz:
        c: StdLibFoo

    foo = StdLibFoo(a='Foo', b=1)
    yield foo, StdLibBar(c=foo)

    foo = PydanticFoo(a='Foo', b=1)
    yield foo, PydanticBar(c=foo)

    foo = PydanticFoo(a='Foo', b=1)
    yield foo, StdLibBaz(c=foo)

    foo = StdLibFoo(a='Foo', b=1)
    yield foo, PydanticBaz(c=foo)

@pytest.mark.parametrize('foo,bar', gen_2162_dataclasses())
def test_issue_2162(foo, bar):
    assert dataclasses.asdict(foo) == dataclasses.asdict(bar.c)
    assert dataclasses.astuple(foo) == dataclasses.astuple(bar.c)
    assert foo == bar.c

def test_issue_2383():
    @dataclasses.dataclass
    class A:
        s: str

        def __hash__(self):
            return 123

    class B(pydantic.BaseModel):
        a: A

    a = A('')
    b = B(a=a)

    assert hash(a) == 123
    assert hash(b.a) == 123

def test_issue_2398():
    @dataclasses.dataclass(order=True)
    class DC:
        num: int = 42

    class Model(pydantic.BaseModel):
        dc: DC

    real_dc = DC()
    model = Model(dc=real_dc)

    # This works as expected.
    assert real_dc <= real_dc
    assert model.dc <= model.dc
    assert real_dc <= model.dc

def test_issue_2424():
    @dataclasses.dataclass
    class Base:
        x: str

    @dataclasses.dataclass
    class Thing(Base):
        y: str = dataclasses.field(default_factory=str)

    assert Thing(x='hi').y == ''

    @pydantic.dataclasses.dataclass
    class ValidatedThing(Base):
        y: str = dataclasses.field(default_factory=str)

    assert Thing(x='hi').y == ''
    assert ValidatedThing(x='hi').y == ''

def test_issue_2541():
    @dataclasses.dataclass(frozen=True)
    class Infos:
        id: int

    @dataclasses.dataclass(frozen=True)
    class Item:
        name: str
        infos: Infos

    class Example(BaseModel):
        item: Item

    e = Example.parse_obj({'item': {'name': 123, 'infos': {'id': '1'}}})
    assert e.item.name == '123'
    assert e.item.infos.id == 1
    with pytest.raises(dataclasses.FrozenInstanceError):
        e.item.infos.id = 2

def test_issue_2555():
    @dataclasses.dataclass
    class Span:
        first: int
        last: int

    @dataclasses.dataclass
    class LabeledSpan(Span):
        label: str

    @dataclasses.dataclass
    class BinaryRelation:
        subject: LabeledSpan
        object: LabeledSpan
        label: str

    @dataclasses.dataclass
    class Sentence:
        relations: BinaryRelation

    class M(pydantic.BaseModel):
        s: Sentence

    assert M.schema()

def test_issue_2594():
    @dataclasses.dataclass
    class Empty:
        pass

    @pydantic.dataclasses.dataclass
    class M:
        e: Empty

    assert isinstance(M(e={}).e, Empty)

def test_schema_description_unset():
    @pydantic.dataclasses.dataclass
    class A:
        x: int

    assert 'description' not in A.__pydantic_model__.schema()

    @pydantic.dataclasses.dataclass
    @dataclasses.dataclass
    class B:
        x: int

    assert 'description' not in B.__pydantic_model__.schema()

def test_schema_description_set():
    @pydantic.dataclasses.dataclass
    class A:
        """my description"""

        x: int

    assert A.__pydantic_model__.schema()['description'] == 'my description'

    @pydantic.dataclasses.dataclass
    @dataclasses.dataclass
    class B:
        """my description"""

        x: int

    assert A.__pydantic_model__.schema()['description'] == 'my description'

def test_issue_3011():
    @dataclasses.dataclass
    class A:
        thing_a: str

    class B(A):
        thing_b: str

    class Config:
        arbitrary_types_allowed = True

    @pydantic.dataclasses.dataclass(config=Config)
    class C:
        thing: A

    b = B('Thing A')
    c = C(thing=b)
    assert c.thing.thing_a == 'Thing A'

def test_issue_3162():
    @dataclasses.dataclass
    class User:
        id: int
        name: str

    class Users(BaseModel):
        user: User
        other_user: User

    assert Users.schema() == {
        'title': 'Users',
        'type': 'object',
        'properties': {'user': {'$ref': '#/definitions/User'}, 'other_user': {'$ref': '#/definitions/User'}},
        'required': ['user', 'other_user'],
        'definitions': {
            'User': {
                'title': 'User',
                'type': 'object',
                'properties': {'id': {'title': 'Id', 'type': 'integer'}, 'name': {'title': 'Name', 'type': 'string'}},
                'required': ['id', 'name'],
            }
        },
    }

def test_discrimated_union_basemodel_instance_value():
    @pydantic.dataclasses.dataclass
    class A:
        l: Literal['a']

    @pydantic.dataclasses.dataclass
    class B:
        l: Literal['b']

    @pydantic.dataclasses.dataclass
    class Top:
        sub: Union[A, B] = dataclasses.field(metadata=dict(discriminator='l'))

    t = Top(sub=A(l='a'))
    assert isinstance(t, Top)
    assert Top.__pydantic_model__.schema() == {
        'title': 'Top',
        'type': 'object',
        'properties': {
            'sub': {
                'title': 'Sub',
                'discriminator': {'propertyName': 'l', 'mapping': {'a': '#/definitions/A', 'b': '#/definitions/B'}},
                'anyOf': [{'$ref': '#/definitions/A'}, {'$ref': '#/definitions/B'}],
            }
        },
        'required': ['sub'],
        'definitions': {
            'A': {
                'title': 'A',
                'type': 'object',
                'properties': {'l': {'title': 'L', 'enum': ['a'], 'type': 'string'}},
                'required': ['l'],
            },
            'B': {
                'title': 'B',
                'type': 'object',
                'properties': {'l': {'title': 'L', 'enum': ['b'], 'type': 'string'}},
                'required': ['l'],
            },
        },
    }

def test_post_init_after_validation():
    @dataclasses.dataclass
    class SetWrapper:
        set: Set[int]

        def __post_init__(self):
            assert isinstance(
                self.set, set
            ), f"self.set should be a set but it's {self.set!r} of type {type(self.set).__name__}"

    class Model(pydantic.BaseModel, post_init_call='after_validation'):
        set_wrapper: SetWrapper

    model = Model(set_wrapper=SetWrapper({1, 2, 3}))
    json_text = model.json()
    assert Model.parse_raw(json_text) == model

def test_keeps_custom_properties():
    class StandardClass:
        """Class which modifies instance creation."""

        a: str

        def __new__(cls, *args, **kwargs):
            instance = super().__new__(cls)

            instance._special_property = 1

            return instance

    StandardLibDataclass = dataclasses.dataclass(StandardClass)
    PydanticDataclass = pydantic.dataclasses.dataclass(StandardClass)

    clases_to_test = [StandardLibDataclass, PydanticDataclass]

    test_string = 'string'
    for cls in clases_to_test:
        instance = cls(a=test_string)
        assert instance._special_property == 1
        assert instance.a == test_string

def test_ignore_extra():
    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.ignore))
    class Foo:
        x: int

    foo = Foo(**{'x': '1', 'y': '2'})
    assert foo.__dict__ == {'x': 1, '__pydantic_initialised__': True}

def test_ignore_extra_subclass():
    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.ignore))
    class Foo:
        x: int

    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.ignore))
    class Bar(Foo):
        y: int

    bar = Bar(**{'x': '1', 'y': '2', 'z': '3'})
    assert bar.__dict__ == {'x': 1, 'y': 2, '__pydantic_initialised__': True}

def test_allow_extra():
    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.allow))
    class Foo:
        x: int

    foo = Foo(**{'x': '1', 'y': '2'})
    assert foo.__dict__ == {'x': 1, 'y': '2', '__pydantic_initialised__': True}

def test_allow_extra_subclass():
    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.allow))
    class Foo:
        x: int

    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.allow))
    class Bar(Foo):
        y: int

    bar = Bar(**{'x': '1', 'y': '2', 'z': '3'})
    assert bar.__dict__ == {'x': 1, 'y': 2, 'z': '3', '__pydantic_initialised__': True}

def test_forbid_extra():
    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.forbid))
    class Foo:
        x: int

    with pytest.raises(TypeError, match=re.escape("__init__() got an unexpected keyword argument 'y'")):
        Foo(**{'x': '1', 'y': '2'})

def test_post_init_allow_extra():
    @pydantic.dataclasses.dataclass(config=dict(extra=Extra.allow))
    class Foobar:
        a: int
        b: str

        def __post_init__(self):
            self.a *= 2

    assert Foobar(a=1, b='a', c=4).__dict__ == {'a': 2, 'b': 'a', 'c': 4, '__pydantic_initialised__': True}

def test_self_reference_dataclass():
    @pydantic.dataclasses.dataclass
    class MyDataclass:
        self_reference: 'MyDataclass'

    assert MyDataclass.__pydantic_model__.__fields__['self_reference'].type_ is MyDataclass


import asyncio
import json

from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hunderline, hcode, hlink
from aiogram.dispatcher.filters import Text
from config import token
from test import morph

from main import check_news_update

bot = Bot(token=token, parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot)

def get_json(ner, date):
    dict_news = list()

    with open("news_dict.json", "r", encoding="utf-8") as read_file:
        data = json.load(read_file)
        day = None
        month = None
        year = None
        print('gf')
        for new in data.keys():
            ner_tec, _ = morph(str(data[new]['article_full_desc']))
            _, data_tec = morph(str(data[new]['article_data']))
            c = True
            for n in ner:
                if n not in ner_tec:
                    c = False
            if len(date) != 0:
                day = date.day
                month = date.month
                year = date.year
            for d in data_tec:
                if day is not None and day != d.day:
                    c = False
                if month is not None and month != d.day:
                    c = False
                if year is not None and year != d.day:
                    c = False
            if c == True:
                dict_news.append([data[new]['article_data'], data[new]['article_full_desc']])
                print(dict_news)
    return dict_news

@dp.message_handler(content_types=types.ContentTypes.TEXT)
async def process_text_message(message: types.Message):
    text,r=morph(message.text)
    list_news = get_json(text,r)
    print(list_news)
    for news in list_news:
        result = str(news[0]) + "\n" + str(news[1])
        await message.answer(result)
    else:
        await message.answer("Нет таких новостей")

    await message.answer("1")

# @dp.message_handler(Text(equals="Сводка"))
# async def get_news_summary(message: types.Message):
#     with open("news_dict.json",encoding="utf-8") as file:
#         news_dict = json.load(file)
#
#     for k, v in sorted(news_dict.items())[-5:]:
#         text = prediction(message.text)

if __name__ == '__main__':
    executor.start_polling(dp)


"""Calcula el precio de la energía diario a partir de los precio horarios"""
import pathlib

from utils import read_format_hourly_prices, resample_hourly_prices

base_path = pathlib.Path.cwd()
cleansed_path = base_path.joinpath("data_lake/cleansed")
business_path = base_path.joinpath("data_lake/business")

def compute_daily_prices(
    source_path=cleansed_path,
    target_path=business_path,
    source_filename="precios-horarios.csv",
    target_namefile="precios-diarios.csv",
):
    """Calcula los precios promedios diarios.

    Usael archivo data_lake/cleansed/precios-horarios.csv, calcula el precio
    promedio diario (sobre las 24 horas del dia) para cada uno de los dias. Las
    columnas del archivo data_lake/business/precios-diarios.csv son:

    * fecha: fecha en formato YYYY-MM-DD
    * precio: precio promedio diario de la electricidad en la bolsa nacional
    """

    df_hourly_prices = read_format_hourly_prices(source_path, filename=source_filename)

    df_daily_prices = resample_hourly_prices(df_hourly_prices, freq="D")

    df_daily_prices.to_csv(target_path.joinpath(target_namefile))

if __name__ == "__main__":
    import doctest

    compute_daily_prices()
    doctest.testmod()


import collections
import heapq
class Solution:
    def networkDelayTime(self, times: list[list[int]], n: int, k: int) -> int:
        graph = collections.defaultdict(list)
        for u, v, w in times:
            graph[u].append((w, v))
        hq = [(0, k)]
        dist = collections.defaultdict(int)
        while hq:
            weight, node = heapq.heappop(hq)
            if node not in dist:
                dist[node] = weight
                for next_weight, next in graph[node]:
                    total_weight = next_weight + weight
                    heapq.heappush(hq, (total_weight, next))

        if len(dist) == n:
            return max(dist.values())
        return -1
temp = Solution()
print(temp.networkDelayTime([[2,1,1],[2,3,1],[3,4,1]], 4, 2))


def minigame():
 import pygame
 import sys
 import pictures
 import random

 status = 'alive'
 zombie_size = [50,100,150,200,250,300]
 obstacle_list = []
 bg_pos = 0
 move= 0
 side = 0
 score = 0

 game_screen = pygame.display.set_mode((608,342)) #creates a screen 1024 pixels wide and 576 pixels long
 clock = pygame.time.Clock() # creates clock object, this will be used later to control the fps

 def move_bg():
  game_screen.blit(background,(bg_pos,0))
  game_screen.blit(background,(bg_pos+608,0))

 def new_obstacle():
  z_size = random.choice(zombie_size)
  new_obstacle = obstacle.get_rect(center =(800,z_size))
  return new_obstacle

 def move_obstacle(obstacle):
   for obstacle in obstacle_list:
     obstacle.centerx = obstacle.centerx -1

 def obstacle_screen(obstacle):
  for obstacles in obstacle_list:
    game_screen.blit(obstacle, obstacles)

 def death (obstacle):
  status = 'alive'
  for obstacle in obstacle_list:
    if avatar_bound.colliderect(obstacle):
     status = 'dead'
  return status

 pygame.init() #initialize pygame module

 #uploading all the necessary images
 background = pygame.image.load('pictures/bg.jpg').convert()
 avatar = pygame.image.load('pictures/avatar.png').convert_alpha()
 obstacle = pygame.image.load('pictures/zombie.png').convert_alpha()
 gameover = pygame.image.load('pictures/gameover.jpg').convert()
 gamewin = pygame.image.load('pictures/win.webp').convert()

 #transforming and scaling images
 avatar = pygame.transform.scale(avatar, (58, 62))
 obstacle = pygame.transform.scale(obstacle, (60, 80))
 gameover= pygame.transform.scale(gameover,(608,342))
 gamewin= pygame.transform.scale(gamewin,(608,342))
 avatar_bound = avatar.get_rect(center =(50,150)) # get rectangle around surface this will help us check for collisions

 add_obstacle = pygame.USEREVENT
 pygame.time.set_timer(add_obstacle, 2200) #every 1500 millseconds event

 while True:
  # write code to exit out of module (add score parameters
  for event in pygame.event.get():
    if event.type == pygame.QUIT: #or score reaches 10
     pygame.quit()
     sys.exit()
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_UP or event.key == ord('w'):
            move =0
            move = move - 3
        if event.key == pygame.K_DOWN or event.key == ord('s'):
            move =0
            move = move + 3
        if event.key == pygame.K_LEFT or event.key == ord('a'):
            side = 0
            side = side - 3
        if event.key == pygame.K_RIGHT or event.key == ord('d'):
            side = 0
            side = side + 3
    if event.type == pygame.KEYUP:
       side = 0
       move = 0
    if event.type == add_obstacle :
       obstacle_list.append(new_obstacle())

  bg_pos = bg_pos-1
  game_screen.blit(background,(bg_pos,0)) # block transfer of bg image, upper left corner at (0,0)
  move_bg()
  if bg_pos <= -608:
    bg_pos = 0

  if status == 'alive' and  score<= 20:
   move_obstacle(obstacle_list)
   obstacle_screen(obstacle)
   game_screen.blit(avatar, avatar_bound)
   # controlling movements of avatar
   avatar_bound.centery = avatar_bound.centery + move
   avatar_bound.centerx = avatar_bound.centerx + side
   status = death(obstacle_list)
   score = score + 0.01

  elif status == 'dead':
    game_screen.blit(gameover,(-20,0))

  elif score >= 20:
     game_screen.blit(gamewin,(0,0))

  pygame.display.update() # updating the display screen
  clock.tick(100) #updates 100 times in a second


from setuptools import setup, find_packages
from os import path
from io import open

here = path.abspath(path.dirname(__file__))
reqs = []

with open(path.join(here, "README.md"), encoding="utf-8") as f:
    long_description = f.read()

with open(path.join(here, "requirements.txt"), encoding="utf-8") as f:
    read_lines = f.readlines()
    reqs = [each.strip() for each in read_lines]

setup(
    name="decimaljs",
    version="1.0.4",
    description="An arbitrary-precision Decimal type for JavaScript to Python",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/kirankotari/decimaljs",
    author="Kiran Kumar Kotari",
    author_email="kirankotari@live.com",
    install_requires=reqs,
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "Topic :: Software Development :: Build Tools",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3.5",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
    ],
    keywords="decimal.js decimal decimaljs",
    packages=find_packages(where=".", exclude=["tests"]),
    include_package_data=True,
)


# -*- coding: utf-8 -*-

#  Licensed under the Apache License, Version 2.0 (the "License"); you may
#  not use this file except in compliance with the License. You may obtain
#  a copy of the License at
#
#       https://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#  License for the specific language governing permissions and limitations
#  under the License.

"""linebot.models.actions module."""

from abc import ABCMeta

from future.utils import with_metaclass

from .base import Base

def get_action(action):
    """Get action."""
    action_obj = Base.get_or_new_from_json_dict_with_types(
        action, {
            'postback': PostbackAction,
            'message': MessageAction,
            'uri': URIAction,
            'datetimepicker': DatetimePickerAction,
            'camera': CameraAction,
            'cameraRoll': CameraRollAction,
            'location': LocationAction,
            'richmenuswitch': RichMenuSwitchAction,
        }
    )
    return action_obj

def get_actions(actions):
    """Get actions."""
    new_actions = []
    if actions:
        for action in actions:
            action_obj = get_action(action)
            if action_obj:
                new_actions.append(action_obj)

    return new_actions

class Action(with_metaclass(ABCMeta, Base)):
    """Abstract base class of Action."""

    def __init__(self, **kwargs):
        """__init__ method.

        :param kwargs:
        """
        super(Action, self).__init__(**kwargs)

        self.type = None

class PostbackAction(Action):
    """PostbackAction.

    https://developers.line.me/en/docs/messaging-api/reference/#postback-action

    When a control associated with this action is tapped,
    a postback event is returned via webhook with the specified string in the data property.
    """

    def __init__(
        self,
        label=None,
        data=None,
        display_text=None,
        text=None,
        input_option=None,
        fill_in_text=None,
        **kwargs
    ):
        """__init__ method.

        :param str label: Label for the action.
        :param str data: String returned via webhook
            in the postback.data property of the postback event.
        :param str display_text: Text displayed in the chat as a message sent by
            the user when the action is performed.
        :param str text: Deprecated. Text displayed in the chat as a message sent by
            the user when the action is performed. Returned from the server through a webhook.
        :param kwargs:
        """
        super(PostbackAction, self).__init__(**kwargs)

        self.type = 'postback'
        self.label = label
        self.data = data
        self.display_text = display_text
        self.text = text
        self.input_option = input_option
        self.fill_in_text = fill_in_text

class MessageAction(Action):
    """MessageAction.

    https://developers.line.me/en/docs/messaging-api/reference/#message-action

    When a control associated with this action is tapped,
    the string in the text property is sent as a message from the user.
    """

    def __init__(self, label=None, text=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action.
        :param str text: Text sent when the action is performed.
        :param kwargs:
        """
        super(MessageAction, self).__init__(**kwargs)

        self.type = 'message'
        self.label = label
        self.text = text

class URIAction(Action):
    """URIAction.

    https://developers.line.me/en/docs/messaging-api/reference/#uri-action

    When a control associated with this action is tapped,
    the URI specified in the uri property is opened.
    """

    def __init__(self, label=None, uri=None, alt_uri=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
            Max: 20 characters
        :param str uri: URI opened when the action is performed.
        :param alt_uri: URI opened when the desktop app.
        :type alt_uri: T <= :py:class:`linebot.models.actions.AltUri`
        :param kwargs:
        """
        super(URIAction, self).__init__(**kwargs)

        self.type = 'uri'
        self.label = label
        self.uri = uri
        self.alt_uri = self.get_or_new_from_json_dict(alt_uri, AltUri)

class AltUri(with_metaclass(ABCMeta, Base)):
    """AltUri.

    https://github.com/line/line-bot-sdk-python/issues/155

    URI opened when the desktop app.
    """

    def __init__(self, desktop=None, **kwargs):
        """__init__ method.

        :param str desktop: URI opened on LINE for macOS and Windows
            when the action is performed.
            If the altUri.desktop property is set,
            the uri property is ignored on LINE for macOS and Windows.
        :param kwargs:
        """
        super(AltUri, self).__init__(**kwargs)

        self.desktop = desktop

class DatetimePickerAction(Action):
    """DatetimePickerAction.

    https://developers.line.me/en/docs/messaging-api/reference/#datetime-picker-action

    When a control associated with this action is tapped,
    a postback event is returned via webhook with the date and time
    selected by the user from the date and time selection dialog.
    The datetime picker action does not support time zones.
    """

    def __init__(self, label=None, data=None, mode=None,
                 initial=None, max=None, min=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param str data: String returned via webhook
            in the postback.data property of the postback event
        :param str mode: Action mode
            date: Pick date
            time: Pick time
            datetime: Pick date and time
        :param str initial: Initial value of date or time
        :param str max: Largest date or time value that can be selected.
            Must be greater than the min value.
        :param str min: Smallest date or time value that can be selected.
            Must be less than the max value.
        :param kwargs:
        """
        super(DatetimePickerAction, self).__init__(**kwargs)

        self.type = 'datetimepicker'
        self.label = label
        self.data = data
        self.mode = mode
        self.initial = initial
        self.max = max
        self.min = min

class CameraAction(Action):
    """CameraAction.

    https://developers.line.me/en/reference/messaging-api/#camera-action

    This action can be configured only with quick reply buttons.
    When a button associated with this action is tapped,
    the camera screen in the LINE app is opened.
    """

    def __init__(self, label=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param kwargs:
        """
        super(CameraAction, self).__init__(**kwargs)

        self.type = 'camera'
        self.label = label

class CameraRollAction(Action):
    """CameraRollAction.

    https://developers.line.me/en/reference/messaging-api/#camera-roll-action

    This action can be configured only with quick reply buttons.
    When a button associated with this action is tapped,
    the camera roll screen in the LINE app is opened.
    """

    def __init__(self, label=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param kwargs:
        """
        super(CameraRollAction, self).__init__(**kwargs)

        self.type = 'cameraRoll'
        self.label = label

class LocationAction(Action):
    """LocationRollAction.

    https://developers.line.me/en/reference/messaging-api/#location-action

    This action can be configured only with quick reply buttons.
    When a button associated with this action is tapped,
    the location screen in the LINE app is opened.
    """

    def __init__(self, label=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param kwargs:
        """
        super(LocationAction, self).__init__(**kwargs)

        self.type = 'location'
        self.label = label

class RichMenuSwitchAction(Action):
    """RichMenuSwitchAction.

    https://developers.line.biz/en/reference/messaging-api/#richmenu-switch-action

    This action can be configured only with rich menus.
    It can't be used for Flex Messages or quick replies.
    When you tap a rich menu associated with this action,
    you can switch between rich menus,
    and a postback event including the rich menu alias ID selected
     by the user is returned via a webhook.
    """

    def __init__(self, label=None, rich_menu_alias_id=None, data=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param str rich_menu_alias_id: Rich menu alias ID to switch to.
        :param str data: String returned by the postback.data property
         of the postback event via a webhook
        :param kwargs:
        """
        super(RichMenuSwitchAction, self).__init__(**kwargs)

        self.type = 'richmenuswitch'
        self.label = label
        self.rich_menu_alias_id = rich_menu_alias_id
        self.data = data


import fresh_tomatoes
import media
import requests
import json
import config

youtube_suffix = config.youtube_key
youtube_prefix = 'https://www.youtube.com/watch?v='

# Movie list -- Here you can add and subtract movies as your tastes change

movie_list = ["There Will Be Blood", "The Life Aquatic", "Unforgiven",
              "Gladiator", "About Time", "The 'Burbs"]

movies = []

def get_info(video):
    """Fetches movie info from Open Movie Database"""

    # Request data from Youtube

    youtube = requests.get('https://www.googleapis.com/youtube/v3/search?part=s'
                           'nippet&q=' + video + 'trailer&maxResults=1&key=' +
                           youtube_suffix, timeout=20)
    youtube_str = youtube.text
    youtube_dict = json.loads(youtube_str)
    video_id = youtube_dict['items'][0]['id']['videoId']
    video_url = youtube_prefix + video_id

    # Request data from OMDB

    result = requests.get('http://www.omdbapi.com/?t=' + video + '&y=&plot='
                          'short&r=json', timeout=20)
    resp_str = result.text

    # Convert data into a python dictionary
    # http://stackoverflow.com/questions/12788217/extract-single-value-from-json-response-python

    resp_dict = json.loads(resp_str)

    trailer = video_url
    title = resp_dict["Title"]
    poster = resp_dict["Poster"]
    release = resp_dict["Released"]
    rating = resp_dict["Rated"]
    runtime = resp_dict["Runtime"]
    genre = resp_dict["Genre"]
    director = resp_dict["Director"]
    plot = resp_dict["Plot"]
    actors = resp_dict["Actors"]

    movies.append(media.Movie(trailer, title, poster, release, rating, runtime,
                              genre, director, plot, actors))

# Create movie instances and add them to the movies list

for movie in movie_list:
    get_info(movie)

fresh_tomatoes.open_movies_page(movies)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('ventas', '0075_auto_20161016_1522'),
    ]

    operations = [
        migrations.RenameField(
            model_name='comanda',
            old_name='tiempo_estimado_elaboracion',
            new_name='tiempo_estimado_procesamiento',
        ),
        migrations.AlterField(
            model_name='comanda',
            name='area_solicitante',
            field=models.ForeignKey(related_name='area_solicitante_comanda', verbose_name=b'Area Solicitante', to='bar.Sector'),
        ),
        migrations.AlterField(
            model_name='comanda',
            name='fecha_hora_pedido_comanda',
            field=models.DateTimeField(verbose_name=b'Fecha/hora Comanda'),
        ),
        migrations.AlterField(
            model_name='comanda',
            name='numero_pedido',
            field=models.ForeignKey(verbose_name=b'Numero de Pedido', to='ventas.Pedido'),
        ),
        migrations.AlterField(
            model_name='comanda',
            name='producto_a_entregar',
            field=models.ForeignKey(verbose_name=b'Producto Solicitado', to='stock.ProductoVenta'),
        ),
    ]


#!/usr/bin/env python3

import os
import sys
import urllib.request

from flask import (
    Flask,
    flash,
    jsonify,
    make_response,
    redirect,
    render_template,
    request,
)
from werkzeug.utils import secure_filename

from scripts import predict_model
from scripts import mongodb
from scripts import train_model

app = Flask(__name__)
app.config["JSONIFY_PRETTYPRINT_REGULAR"] = True

ENVIRONMENT_WINDOWS = True

@app.route("/")
def index():
    return "Application Alive"

@app.route("/api/v1.0/users", methods=["GET"])
def get_users():
    return jsonify({"Users": mongodb.get_list_users()})

@app.route("/api/v1.0/experiments/<user>", methods=["GET"])
def get_experiments(user):
    user = user.lower()

    file_dir_data = os.listdir("data/")
    if user not in file_dir_data:
        return make_response(jsonify({"error": "User Not Found"}), 404)

    else:
        file_dir_user = os.listdir("data/{}".format(user))
        return jsonify({"user": user, "experiments": file_dir_user})

@app.route("/api/v1.0/train/<user>/<experiment_name>", methods=["GET"])
def train_experiment(user, experiment_name):
    user = user.lower()
    experiment_name = experiment_name.lower()

    file_dir_data = os.listdir("data/")
    if user not in file_dir_data:
        return make_response(jsonify({"error": "User Not Found"}), 404)

    file_dir_user = os.listdir("data/{}".format(user))

    if experiment_name not in file_dir_user:
        return make_response(jsonify({"error": "Experiment Not Found"}), 404)

    model_def = "data/{}/{}/model_definition.yaml".format(user, experiment_name)
    data_csv = "data/{}/{}/train_data.csv".format(user, experiment_name)
    log_file = "data/{}/{}/training.log".format(user, experiment_name)

    if ENVIRONMENT_WINDOWS:
        output_dir = "data\{}\{}".format(user, experiment_name)
    else:
        output_dir = "data/{}/{}".format(user, experiment_name)

    res = train_model.train_model(
        model_def, output_dir, data_csv, experiment_name, log_file
    )

    if res != True:
        return jsonify(
            {
                "user": user,
                "response": res,
                "model_definition": model_def,
                "data_csv": data_csv,
                "log_file": log_file,
                "output_dir": output_dir,
            }
        )

    return jsonify({"user": user, "response": "Training in Progress"})

@app.route("/api/v1.0/predict/<user>/<experiment_name>", methods=["POST"])
def predict_experiment(user, experiment_name):
    file = request.files["file"]

    if file.filename != "":
        filename = secure_filename(file.filename)

        if "predict" not in os.listdir("data/{}/{}".format(user, experiment_name)):
            os.mkdir("data/{}/{}/predict/".format(user, experiment_name))

        file.save("data/{}/{}/predict/{}".format(user, experiment_name, filename))

        return jsonify(
            {"result": {"dog": 0.85, "cat": 0.15}, "exp": experiment_name, "user": user}
        )

    return jsonify({"response": "Error"})

@app.route("/api/v1.0/register/<user>", methods=["GET"])
def register_user(user):
    user = user.lower()
    dir_list_users = os.listdir("data/")
    if user in dir_list_users:
        return make_response(jsonify({"error": "User Already Exists"}), 420)
    else:
        os.mkdir("data/{}".format(user))
        return jsonify({"user": user, "response": "User Successfully Created"})

@app.route("/api/v1.0/register/<user>/<experiment_name>", methods=["GET"])
def register_experiment(user, experiment_name):
    user = user.lower()
    experiment_name = experiment_name.lower()

    dir_list_users = os.listdir("data/")
    if user in dir_list_users:
        dir_list_experiments = os.listdir("data/{}/".format(user))
        if experiment_name in dir_list_experiments:
            return make_response(jsonify({"error": "Experiment Already Exists"}), 420)
        else:
            os.mkdir("data/{}/{}".format(user, experiment_name))
            return jsonify(
                {
                    "user": user,
                    "experiment": experiment_name,
                    "response": "Experiment Successfully Created",
                }
            )
    else:
        return make_response(jsonify({"error": "User Does Not Exist"}), 420)

@app.route("/api/v1.0/remove/<user>", methods=["GET"])
def remove_user(user):
    user = user.lower()
    dir_list_users = os.listdir("data/")
    if user not in dir_list_users:
        return make_response(jsonify({"error": "User Does Not Exist"}), 420)
    else:
        dir_list_experiments = os.listdir("data/{}".format(user))
        if len(dir_list_experiments) == 0:
            os.rmdir("data/{}".format(user))
            return jsonify({"user": user, "response": "User Successfully Removed"})
        else:
            return jsonify(
                {
                    "user": user,
                    "response": "User Experiments still exist",
                    "experiments": dir_list_experiments,
                }
            )

@app.route("/api/v1.0/remove/<user>/<experiment_name>", methods=["GET"])
def remove_experiment(user, experiment_name):
    user = user.lower()
    experiment_name = experiment_name.lower()

    dir_list_users = os.listdir("data/")
    if user in dir_list_users:
        dir_list_experiments = os.listdir("data/{}/".format(user))
        if experiment_name in dir_list_experiments:
            os.rmdir("data/{}/{}".format(user, experiment_name))
            return jsonify(
                {
                    "user": user,
                    "experiment": experiment_name,
                    "response": "Experiment Successfully Removed",
                }
            )
        else:
            return make_response(jsonify({"error": "Experiment Does Not Exist"}), 420)
    else:
        return make_response(jsonify({"error": "User Does Not Exist"}), 420)

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({"error": "Request Not Found"}), 404)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port="5000")


import vtk

def main():
    colors = vtk.vtkNamedColors()

    # Set the background color.
    colors.SetColor("bkg", [0.2, 0.3, 0.4, 1.0])

    # Create a sphere to deform
    sphere = vtk.vtkSphereSource()
    sphere.SetThetaResolution(51)
    sphere.SetPhiResolution(17)
    sphere.Update()
    bounds = sphere.GetOutput().GetBounds()

    # Create a filter to color the sphere
    ele = vtk.vtkElevationFilter()
    ele.SetInputConnection(sphere.GetOutputPort())
    ele.SetLowPoint(0,0,-0.5);
    ele.SetHighPoint(0,0,0.5);
    ele.SetLowPoint((bounds[1] + bounds[0]) / 2.0,
                    (bounds[3] + bounds[2]) / 2.0,
                    -bounds[5]);
    ele.SetHighPoint((bounds[1] + bounds[0]) / 2.0,
                     (bounds[3] + bounds[2]) / 2.0,
                     bounds[5]);
    ele.Update()

    # Create a mesh to deform the sphere
    pts = vtk.vtkPoints()
    pts.SetNumberOfPoints(6)
    pts.SetPoint(0,
                 bounds[0] - 0.1 * (bounds[1] - bounds[0]),
                 (bounds[3] + bounds[2]) / 2.0,
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(1,
                 bounds[1] + 0.1 * (bounds[1] - bounds[0]),
                 (bounds[3] + bounds[2]) / 2.0,
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(2,
                 (bounds[1] + bounds[0]) / 2.0,
                 bounds[2] - 0.1 * (bounds[3] - bounds[2]),
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(3,
                 (bounds[1] + bounds[0]) / 2.0,
                 bounds[3] + 0.1 * (bounds[3] - bounds[2]),
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(4,
                 (bounds[1] + bounds[0]) / 2.0,
                 (bounds[3] + bounds[2]) / 2.0,
                 bounds[4] - 0.1 * (bounds[5] - bounds[4]))
    pts.SetPoint(5,
                 (bounds[1] + bounds[0]) / 2.0,
                 (bounds[3] + bounds[2]) / 2.0,
                 bounds[5] + 0.1 * (bounds[5] - bounds[4]))
    tris = vtk.vtkCellArray()

    cells = [[2, 0, 4], [1, 2, 4], [3, 1, 4], [0, 3, 4], [0, 2, 5], [2, 1, 5], [1, 3, 5], [3, 0, 5]]

    for cell in cells:
        tris.InsertNextCell(3)
        for c in cell:
            tris.InsertCellPoint(c)

    pd = vtk.vtkPolyData()
    pd.SetPoints(pts)
    pd.SetPolys(tris)

    meshMapper = vtk.vtkPolyDataMapper()
    meshMapper.SetInputData(pd)
    meshActor = vtk.vtkActor()
    meshActor.SetMapper(meshMapper)
    meshActor.GetProperty().SetRepresentationToWireframe()
    meshActor.GetProperty().SetColor(colors.GetColor3d("Black"))

    deform = vtk.vtkDeformPointSet()
    deform.SetInputData(ele.GetOutput())
    deform.SetControlMeshData(pd)
    deform.Update()

    controlPoint = pts.GetPoint(5)
    pts.SetPoint(5, controlPoint[0],
                 controlPoint[1],
                 bounds[5] + .8 * (bounds[5] - bounds[4]))
    pts.Modified()

    polyMapper = vtk.vtkPolyDataMapper()
    polyMapper.SetInputConnection(deform.GetOutputPort())
    polyActor = vtk.vtkActor()
    polyActor.SetMapper(polyMapper)

    renderer = vtk.vtkRenderer()
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(renderer)
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)

    renderer.AddActor(polyActor)
    renderer.AddActor(meshActor)

    renderer.GetActiveCamera().SetPosition(1,1,1)
    renderer.ResetCamera()
    renderer.SetBackground(colors.GetColor3d("bkg"))

    renWin.SetSize(300,300)
    renWin.Render()

    iren.Start()

if __name__ == '__main__':
    main()


#!/usr/bin/env python

import os.path

import vtk

def get_program_parameters():
    import argparse
    description = 'Decimate polydata.'
    epilogue = '''
    This is an example using vtkDecimatePro to decimate input polydata, if provided, or a sphere otherwise.
    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue)
    parser.add_argument('filename', nargs='?', default=None, help='Optional input filename e.g Torso.vtp.')
    parser.add_argument('reduction', nargs='?', type = float, default=.9, help='Sets the decimation target reduction, (default is 0.9).')
    args = parser.parse_args()
    return args.filename, args.reduction

def main():
    filePath, reduction = get_program_parameters()

    # Define colors
    colors = vtk.vtkNamedColors()
    backFaceColor = colors.GetColor3d("gold")
    inputActorColor = colors.GetColor3d("flesh")
    decimatedActorColor = colors.GetColor3d("flesh")
    colors.SetColor('leftBkg', [0.6, 0.5, 0.4, 1.0])
    colors.SetColor('rightBkg', [0.4, 0.5, 0.6, 1.0])

    if filePath and os.path.isfile(filePath):
        inputPolyData = ReadPolyData(filePath)
        if not inputPolyData:
            inputPolyData = GetSpherePD()
    else:
        inputPolyData = GetSpherePD()

    print("Before decimation")
    print(f"There are {inputPolyData.GetNumberOfPoints()} points.")
    print(f"There are {inputPolyData.GetNumberOfPolys()} polygons.")

    decimate = vtk.vtkDecimatePro()
    decimate.SetInputData(inputPolyData)
    decimate.SetTargetReduction(reduction)
    decimate.PreserveTopologyOn()
    decimate.Update()

    decimated = vtk.vtkPolyData()
    decimated.ShallowCopy(decimate.GetOutput())

    print("After decimation")
    print(f"There are {decimated.GetNumberOfPoints()} points.")
    print(f"There are {decimated.GetNumberOfPolys()} polygons.")
    print(f"Reduction: {(inputPolyData.GetNumberOfPolys() - decimated.GetNumberOfPolys()) / inputPolyData.GetNumberOfPolys()}")

    inputMapper = vtk.vtkPolyDataMapper()
    inputMapper.SetInputData(inputPolyData)

    backFace = vtk.vtkProperty()
    backFace.SetColor(backFaceColor)

    inputActor = vtk.vtkActor()
    inputActor.SetMapper(inputMapper)
    inputActor.GetProperty().SetInterpolationToFlat()
    inputActor.GetProperty().SetColor(inputActorColor)
    inputActor.SetBackfaceProperty(backFace)

    decimatedMapper = vtk.vtkPolyDataMapper()
    decimatedMapper.SetInputData(decimated)

    decimatedActor = vtk.vtkActor()
    decimatedActor.SetMapper(decimatedMapper)
    decimatedActor.GetProperty().SetColor(decimatedActorColor)
    decimatedActor.GetProperty().SetInterpolationToFlat()
    decimatedActor.SetBackfaceProperty(backFace)

    # There will be one render window
    renderWindow = vtk.vtkRenderWindow()
    renderWindow.SetSize(600, 300)

    # And one interactor
    interactor = vtk.vtkRenderWindowInteractor()
    interactor.SetRenderWindow(renderWindow)

    # Define viewport ranges
    # (xmin, ymin, xmax, ymax)
    leftViewport = [0.0, 0.0, 0.5, 1.0]
    rightViewport = [0.5, 0.0, 1.0, 1.0]

    # Setup both renderers
    leftRenderer = vtk.vtkRenderer()
    renderWindow.AddRenderer(leftRenderer)
    leftRenderer.SetViewport(leftViewport)
    leftRenderer.SetBackground((colors.GetColor3d('leftBkg')))

    rightRenderer = vtk.vtkRenderer()
    renderWindow.AddRenderer(rightRenderer)
    rightRenderer.SetViewport(rightViewport)
    rightRenderer.SetBackground((colors.GetColor3d('rightBkg')))

    # Add the sphere to the left and the cube to the right
    leftRenderer.AddActor(inputActor)
    rightRenderer.AddActor(decimatedActor)

    # Shared camera
    # Shared camera looking down the -y axis
    camera = vtk.vtkCamera()
    camera.SetPosition (0, -1, 0)
    camera.SetFocalPoint (0, 0, 0)
    camera.SetViewUp (0, 0, 1)
    camera.Elevation(30)
    camera.Azimuth(30)

    leftRenderer.SetActiveCamera(camera)
    rightRenderer.SetActiveCamera(camera)

    leftRenderer.ResetCamera()
    leftRenderer.ResetCameraClippingRange()

    renderWindow.Render()
    renderWindow.SetWindowName('Decimation')

    interactor.Start()

def ReadPolyData(file_name):
    import os
    path, extension = os.path.splitext(file_name)
    extension = extension.lower()
    if extension == ".ply":
        reader = vtk.vtkPLYReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == ".vtp":
        reader = vtk.vtkXMLpoly_dataReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == ".obj":
        reader = vtk.vtkOBJReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == ".stl":
        reader = vtk.vtkSTLReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == ".vtk":
        reader = vtk.vtkpoly_dataReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == ".g":
        reader = vtk.vtkBYUReader()
        reader.SetGeometryFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    else:
        # Return a None if the extension is unknown.
        poly_data = None
    return poly_data

def GetSpherePD():
    """
    :return: The PolyData representation of a sphere.
    """
    source = vtk.vtkSphereSource()
    source.SetThetaResolution(30)
    source.SetPhiResolution(15)
    source.Update()
    return source.GetOutput()

if __name__ == '__main__':
    main()


from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('test_rdd').getOrCreate()
sc = spark.sparkContext

class TestRDD():
    # Creations
    def test_create_from_dataframe(self):
        df = spark.range(10).toDF('id')
        rdd = df.rdd
        rows = rdd.collect()
        assert len(rows) == 10
        assert rows[9]['id'] == 9

    def test_create_from_collection(self):
        data = [1, 2, 3, 4]
        rdd = sc.parallelize(data, 2)
        list_1 = rdd.collect()
        assert list_1 == [1, 2, 3, 4]
        list_2 = rdd.glom().collect()
        assert list_2 == [[1, 2], [3, 4]]

    def test_create_from_file(self):
        pass

    # Transformations
    def test_map(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.map(lambda word: (word, word[0], len(word)))
        list_1 = rdd_1.collect()
        assert list_1[0] == ('The', 'T', 3)

    def test_filter(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.map(lambda word: (word, word[0], len(word)))
        rdd_2 = rdd_1.filter(lambda record: record[2] == 5)
        list_2 = rdd_2.collect()
        assert list_2 == [('quick', 'q', 5), ('brown', 'b', 5), ('jumps', 'j', 5)]

    def test_sortBy(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.sortBy(lambda word: len(word))
        list_1 = rdd_1.take(5)
        assert list_1 == ['The', 'fox', 'the', 'dog', 'over']

    # Partition Transformations
    def test_mapPartitions(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.mapPartitions(lambda part: [word[::-1] for word in part])
        list_1 = rdd_1.collect()
        assert list_1 == ['ehT', 'kciuq', 'nworb', 'xof', 'spmuj', 'revo', 'eht', 'yzal', 'god']

    def test_foreachPartition(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)

        def func(partition):
            for word in partition:
                print(word[::-1])

        rdd.foreachPartition(func)

    # Actions
    def test_count(self):
        data = range(1, 5)
        rdd = sc.parallelize(data)
        cnt = rdd.count()
        assert cnt == 4

    def test_reduce(self):
        data = range(1, 5)
        rdd = sc.parallelize(data)
        product = rdd.reduce(lambda x, y: x * y)
        assert product == 24

    # Pair RDDs
    def test_keyBy_and_mapValues(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        pair_rdd = sc.parallelize(words).keyBy(lambda word: word.lower()[0])
        rdd_1 = pair_rdd.mapValues(lambda word: word.upper())
        list_1 = rdd_1.take(3)
        assert list_1 == [('t', 'THE'), ('q', 'QUICK'), ('b', 'BROWN')]
        list_2 = rdd_1.keys().collect()
        assert list_2 == ['t', 'q', 'b', 'f', 'j', 'o', 't', 'l', 'd']
        list_3 = rdd_1.values().collect()
        assert list_3[0] == 'THE'

    def test_countByKey(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        pair_rdd = sc.parallelize(words).map(lambda word: (word.lower()[0], word.upper()))
        d = pair_rdd.countByKey()
        assert list(d.items()) == [('t', 2), ('q', 1), ('b', 1), ('f', 1), ('j', 1), ('o', 1), ('l', 1), ('d', 1)]

    def test_reduceByKey(self):
        pair_rdd = sc.parallelize([('a', 1), ('b', 2), ('c', 3), ('b', 2), ('a', 1)])
        rdd_1 = pair_rdd.reduceByKey(lambda x, y: x*y)
        list_1 = rdd_1.collect()
        assert list_1 == [('a', 1), ('b', 4), ('c', 3)]

    # Broadcast Variable
    def test_BV(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        bv_data = {'e': 5, 'j': 10, 'o': 15, 't': 20, 'y': 25}
        bv = sc.broadcast(bv_data)
        bv_value = bv.value
        rdd_1 = rdd.map(lambda word: bv_value.get(word.lower()[0], -1))
        list_1 = rdd_1.collect()
        assert list_1 == [20, -1, -1, -1, 10, 15, 20, -1, -1]

    # Accumulator
    def test_accumulator(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        first_acc = sc.accumulator(value=0)

        def func(word):
            if len(word) == 3:
                first_acc.add(1)

        rdd.foreach(func)
        assert first_acc.value == 4

if __name__ == '__main__':
    test = TestRDD()
    # Call a method here
    test.test_accumulator()
    spark.stop()


import json
from hsfs import util
import humps

class TrainingDatasetSplit:
    TIME_SERIES_SPLIT = "TIME_SERIES_SPLIT"
    RANDOM_SPLIT = "RANDOM_SPLIT"
    TRAIN = "train"
    VALIDATION = "validation"
    TEST = "test"

    def __init__(
        self,
        name,
        split_type,
        percentage=None,
        start_time=None,
        end_time=None,
        **kwargs
    ):
        self._name = name
        self._percentage = percentage
        self._split_type = split_type
        self._start_time = start_time
        self._end_time = end_time

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    @property
    def percentage(self):
        return self._percentage

    @percentage.setter
    def percentage(self, percentage):
        self._percentage = percentage

    @property
    def split_type(self):
        return self._split_type

    @split_type.setter
    def split_type(self, split_type):
        self._split_type = split_type

    @property
    def start_time(self):
        return self._start_time

    @start_time.setter
    def start_time(self, start_time):
        self._start_time = start_time

    @property
    def end_time(self):
        return self._end_time

    @end_time.setter
    def end_time(self, end_time):
        self._end_time = end_time

    def json(self):
        return json.dumps(self, cls=util.FeatureStoreEncoder)

    def to_dict(self):
        return {
            "name": self._name,
            "percentage": self._percentage,
            "splitType": self._split_type,
            "startTime": self._start_time,
            "endTime": self._end_time,
        }

    @classmethod
    def from_response_json(cls, json_dict):
        json_decamelized = humps.decamelize(json_dict)
        return cls(
            name=json_decamelized["name"],
            split_type=json_decamelized.get(
                "split_type", TrainingDatasetSplit.RANDOM_SPLIT
            ),
            percentage=json_decamelized.get("percentage", None),
            start_time=json_decamelized.get("start_time", None),
            end_time=json_decamelized.get("end_time", None),
        )