from __future__ import print_function
from __future__ import division
from __future__ import unicode_literals
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import range
from builtins import *
from past.utils import old_div
from builtins import object
import pykov as pk
import emission.net.ext_service.otp.otp as otp
import emission.net.ext_service.geocoder.nominatim as geo
import emission.core.wrapper.trip_old as to
import emission.core.get_database as edb

import datetime
import random
import math
import urllib.request, urllib.error, urllib.parse
import json
import heapq
import time
import requests
import random
import os

CENTER_OF_CAMPUS = to.Coordinate(37.871790, -122.260005)
RANDOM_RADIUS = .3  # 300 meters around center of campus; for randomization
N_TOP_TRIPS = 3 # Number of top trips we return for the user to look at

class UserBase(object):

    """
    Stores all the users and stores the population of areas
    Also keeps state on other useful things that we need to know, like caches
    """

    def __init__(self):
        self.users = []
        self.crowd_areas = {}
        self.last_info = {}  ## so we only call google maps if we change things
        self.old_trips = None
        self.geocode_cache = {} # fewer calls to google maps

    def add_user(self, user):
        self.users.append(user)

    def add_crowd(self, area):
        self.crowd_areas[area.name] = area

    def get_crowd_info(self, area_name):
        return self.crowd_areas[area_name]

    def geocode_with_cache(self, place):
        coder = geo.Geocoder()
        if place in self.geocode_cache:
            print(self.geocode_cache[place])
            return self.geocode_cache[place]
        else:
            coded = coder.geocode(place)
            self.geocode_cache[place] = coded
            print(coded)
            return coded

the_base = UserBase()

class CampusTrip(object):

    def __init__(self, score_list, time_duration, points, source):
        self.time = score_list[0]
        self.sweat = score_list[1]
        self.beauty = score_list[2]
        self.social = score_list[3]
        self.tot_score = sum(score_list)
        self.time_duration = old_div(time_duration, float(60))
        self.points = points
        self.source = source

    def make_points(self):
        to_return = ""
        for p in self.points:
            to_return += str(p[0])
            to_return += ","
            to_return += str(p[1])
            to_return += ","
        return to_return

    def make_for_browser(self):
        return '%s;%s;%s;%s;%s;%s' % (self.beauty, self.time, self.social, self.sweat, self.time_duration, self.make_points())

    def make_jsn(self):
        return json.dumps({"time" : self.time, "beauty" : self.beauty, "social" : self.social, "sweat" : self.sweat, "duration" : self.time_duration, "points" : self.points})

    def make_json(self):
        return json.dumps(self.make_for_browser())

    def __repr__(self):
        return "total score : %f || source : %s || beauty : %f || sweat : %f || time : %f || social : %f" % (self.tot_score, self.source, self.beauty, self.sweat, self.time, self.social)

    def __eq__(self, other):
        return self.make_points() == other.make_points()

class UserModel(object):

    """
    User Model class
    Can do lots of cool things
    """

    def __init__(self, has_bike=False):
        self.utilities = pk.Chain()
        self.has_bike = has_bike
        self.user_base = the_base

        self.user_base.add_user(self)

        ## Initialize utilities
        self.utilities["sweat"] = 0
        self.utilities["scenery"] = 0
        self.utilities["social"] = 0
        self.utilities["time"] = 0

    def get_top_choice_places(self, start_place, end_place):
        start = self.user_base.geocode_with_cache(start_place)
        end = self.user_base.geocode_with_cache(end_place)
        return self.get_top_choices_lat_lng(start, end)

    def get_all_trips(self, start, end, curr_time=None):
        if curr_time is None:
            curr_time = datetime.datetime.now()
        curr_month = curr_time.month
        curr_year = curr_time.year
        curr_minute = curr_time.minute
        curr_day = curr_time.day
        curr_hour = curr_time.hour
        mode = "WALK"
        if self.has_bike:
            mode = "BICYCLE"

        walk_otp = otp.OTP(os.environ("OTP_SERVER")).route(start, end, "WALK", write_day(curr_month, curr_day, curr_year), write_time(curr_hour, curr_minute), False)
        lst_of_trips = walk_otp.get_all_trips(0, 0, 0)
        tot_trips = lst_of_trips

        return tot_trips

    def get_top_choices_lat_lng(self, start, end, curr_time=None, tot_trips=None):
        testing = True
        if tot_trips is None:
            tot_trips = self.get_all_trips(start, end, curr_time)
            testing = False
        scores = [ ]
        times = get_normalized_times(tot_trips)
        beauty = get_normalized_beauty(tot_trips)
        sweat = get_normalized_sweat(tot_trips, testing=testing)
        for i in range(len(times)):
            scores.append(self.get_score_for_trip(tot_trips[i], times[i], beauty[i], sweat[i]))

        top = self.get_top_n(scores, N_TOP_TRIPS)
        return top

    def get_score_for_trip(self, trip, time, beauty, sweat):
        crowd_score = 0
        lst_of_points = get_route(trip)

        for crowd in self.user_base.crowd_areas.values():
            crowd.update_times(trip.start_time)
            crowd_score += crowd.get_crowd()

        final_time =  -(time * self.utilities["time"])
        final_sweat = -sweat * self.utilities["sweat"]
        final_beauty = (self.utilities['scenery']*beauty)
        final_crowd = (self.utilities['social']*crowd_score)

        final_score_tuple = (final_time, final_sweat, final_beauty, final_crowd)
        print("final_score_tuple : %s" % str(final_score_tuple))
        return CampusTrip(final_score_tuple, get_time_of_trip(trip), lst_of_points, "source")

    def get_top_n(self, lst_of_trips, n):
        return heapq.nlargest(n, lst_of_trips, key=lambda v: v.tot_score)

    def increment_utility(self, which):
        self.utilities[which] += 1

    def increase_utility_by_n(self, which, n):
        self.utilities[which] += n

    def normalize_utilities(self):
        self.utilities.normalize()

    def save_to_db(self):
        db = edb.get_utility_model_db()
        db.insert({"utilities" : self.utilities, "name" : self.name})

    def delta(self, start, end):
        """
        Returns true if anything has changed and we should call google maps...
        Otherwise no.
        """
        if "start" not in self.user_base.last_info or "end" not in self.user_base.last_info or "utilities" not in self.user_base.last_info:
            #print "first delta"
            return True
        return not (start == self.user_base.last_info["start"] and end == self.user_base.last_info["end"] and self.utilities == self.user_base.last_info["utilities"])

    def add_to_last(self, start, end):
        self.user_base.last_info["utilities"] = self.utilities.copy()
        self.user_base.last_info["start"] = start
        self.user_base.last_info["end"] = end

def normalize_noises(noise_areas):
    to_return = []
    for area in noise_areas:
        area.normalize_sounds()
        to_return.append(area)
    return to_return

def get_time_of_trip(trip):
    return (trip.end_time - trip.start_time).seconds

def get_normalized_times(lst_of_trips):
    counter = pk.Vector()
    i = 0
    for trip in lst_of_trips:
        counter[i] = get_time_of_trip(trip)
        i += 1
    counter.normalize()
    to_return = []
    for i in range(len(lst_of_trips)):
        to_return.append(counter[i])
    return to_return

def get_sweat_factor(trip, testing=False):
    chng = get_elevation_change(trip, testing)
    print("chng : %s" % str(chng))
    return 71.112*chng[0] + 148.09

def get_normalized_sweat(lst_of_trips, testing=False):
    counter = pk.Vector()
    i = 0
    for trip in lst_of_trips:
        factor = get_sweat_factor(trip, testing)
        print("sweat_factor : %s" % factor)
        counter[i] = factor
        i += 1
    counter.normalize()
    to_return = []
    for i in range(len(lst_of_trips)):
        to_return.append(counter[i])
    return to_return

def get_normalized_beauty(lst_of_trips):
    counter = pk.Vector()
    i = 0
    for trip in lst_of_trips:
        factor = get_beauty_score_of_trip(trip)
        print("beauty_factor : %s" % factor)
        counter[i] = factor
        i += 1
    counter.normalize()
    to_return = []
    for i in range(len(lst_of_trips)):
        to_return.append(counter[i])
    return to_return

class Area(object):

    """ Area class """

    def __init__(self, name, tl, br, beauty=None, time_to_noise=None):
        self.name = name
        self.bounding_box = (tl, br)
        self.beauty = beauty
        self.time_to_noise = time_to_noise
        self.times = set()

    def point_in_area(self, lat, lng):
        return in_bounding_box(lat, lng, self.bounding_box)

    def add_time(self, time):
        self.times.add(time)

    def get_crowd(self):
        return len(self.times)

    def update_times(self, time_by):
        for time in self.times:
            if time < time_by:
                self.times.remove(time)

    def update_to_now(self):
        self.update_times(datetime.datetime.now())

    def normalize_sounds(self):
        counter = pk.Vector()
        for k,v in self.time_to_noise.items():
            counter[k] = v
        counter.normalize()
        self.time_to_noise = counter

    def __repr__(self):
        return "beauty : %s" % (self.beauty)

def in_bounding_box(lat, lon, bounding_box):
    return bounding_box[1][0] <= lat and lat <= bounding_box[0][0] and bounding_box[0][1] <= lon and lon <= bounding_box[1][1]

def parse_noise():
    noise_file = open("emission/user_model_josh/noise_data.csv")
    sproul_noises, glade_noises, wellmen_noises, leconte_noises = {}, {}, {}, {}
    sproul_tl, sproul_br = (37.870637,-122.259722), (37.868926,-122.259005)
    glade_tl, glade_br = (37.87359,-122.260098), (37.872707,-122.258687)
    wellmen_tl, wellmen_br = (37.873045,-122.263377), (37.872501,-122.261803)
    lecont_tl, lecont_br = (37.873278,-122.256959), (37.872277,-122.25639)
    time = datetime.datetime(2040, 10, 10, 6, 0, 0)
    td = datetime.timedelta(minutes=10)
    for l in noise_file:
        l = l.split(',')
        sproul_noises[time] = float(l[0])
        glade_noises[time] = float(l[1])
        wellmen_noises[time] = float(l[2])
        leconte_noises[time] = float(l[3])
    sproul = Area("sproul", sproul_tl, sproul_br, time_to_noise=sproul_noises)
    glade = Area("glade", glade_tl, glade_br, time_to_noise=glade_noises)
    wellmen = Area("wellmen", wellmen_tl, wellmen_br, time_to_noise=wellmen_noises)
    leconte = Area("leconte", lecont_tl, lecont_br, time_to_noise=leconte_noises)
    return [sproul, glade, wellmen, leconte]

def parse_beauty():
    beauty_file = open("emission/user_model_josh/beauty.csv")
    beauty_areas = [ ]
    for beauty_line in beauty_file:
        beauty_line = beauty_line.split(',')
        name = beauty_line[0]
        tl = (float(beauty_line[1]), float(beauty_line[2]))
        br = (float(beauty_line[5]), float(beauty_line[6]))
        beauty = int(beauty_line[9])
        a = Area(name, tl, br, beauty=beauty)
        beauty_areas.append(a)
    return beauty_areas

def get_noise_score(lat, lng, noises, time):
    tot = 0
    to_return = 0
    for noise_area in noises:
        if noise_area.point_in_area(lat, lng):
            to_return += get_closest(time, noise_area)
    if to_return > 0:
        return to_return
    return .5 ## if point isnt in any mapped area return the average

def get_closest(time, area):
    for k, v in area.time_to_noise.items():
        if time - k < datetime.timedelta(minutes=10):
            return v
    return 0

def get_beauty_score(lat, lng, beauties):
    tot = 0
    for beauty_area in beauties:
        tot += beauty_area.beauty
        if beauty_area.point_in_area(lat, lng):
            return beauty_area.beauty
    return old_div(float(tot), float(len(beauties))) ## if point isnt in any mapped area return the average

def get_beauty_score_of_trip(trip):
    beauties = parse_beauty()
    beauty_score = 0
    tot_points = 0
    for section in trip.sections:
        for point in section.points:
            tot_points += 1
            beauty_score += get_beauty_score(point.get_lat(), point.get_lon(), beauties)
    return old_div(float(beauty_score), float(tot_points))

def get_noise_score_of_trip(trip):
    noises = parse_noise()
    noise_score = 0
    for section in trip.sections:
        for point in section.points:
            tot_points += 1
            noise_score += get_noise_score(point.get_lat(), point.get_lon(), noises)
    return old_div(float(beauty_score), float(tot_points))

def get_route_dict(trip):
    route = []
    for point in trip:
        d = {'lat' : point[0], 'lng' : point[1]}
        route.append(d)
    return route

def get_route(trip):
    i = 0
    lst_of_points = []
    lst_of_points.append( (trip.trip_start_location.get_lat(), trip.trip_start_location.get_lon()) )
    for section in trip.sections:
        for point in section.points:
            if i % 2 == 0:
                lst_of_points.append( (point.get_lat(), point.get_lon()) )
            i += 1
    lst_of_points.append( (trip.trip_end_location.get_lat(), trip.trip_end_location.get_lon()) )
    return lst_of_points

def write_day(month, day, year):
    return "%s-%s-%s" % (month, day, year)

def write_time(hour, minute):
    return "%s:%s" % (hour, minute)

def get_one_random_point_in_radius(crd, radius):
    # From https://gis.stackexchange.com/questions/25877/how-to-generate-random-locations-nearby-my-location
    radius_in_degrees = kilometers_to_degrees(radius)
    x_0 = crd.get_lon()
    y_0 = crd.get_lat()
    u = random.random()
    v = random.random()
    w = radius_in_degrees * math.sqrt(u)
    t = 2 * math.pi * v
    x = w * math.cos(t)
    y = w * math.sin(t)
    x = old_div(float(x), float(math.cos(y_0))) # To account for Earth curvature stuff
    to_return = to.Coordinate(y + y_0, x + x_0)
    return to_return

def kilometers_to_degrees(km):
    ## From stackexchnage mentioned above
    return (old_div(float(km),float(40000))) * 360

def str_time_to_datetme(str_time):
    t = str_time.split(":")
    return datetime.datetime(2040, 10, 10, int(t[0]), int(t[1]), 0)

def make_user_from_jsn(jsn, base):
    value_line = jsn["objects"]["Computer"]["streams"]["userData"]["points"][0]["value"]
    value_line = value_line.split(";")
    start = value_line[0]
    end = value_line[1]

    start = base.geocode_with_cache(start)
    end = base.geocode_with_cache(end)

    time_info = {}
    print(value_line)
    if value_line[2] == "leaveNow":
        time_info["leave"] = True
        time_info["when"] = datetime.datetime.now()
        print("leaveNow")
    elif value_line[2] == "leaveAt":
        time_info["leave"] = True
        time_info["when"] = str_time_to_datetme(value_line[3])
        print("leaveAt")
    elif value_line[2] == "thereBy":
        time_info["leave"] = False
        time_info["when"] = str_time_to_datetme(value_line[3])
        print("arriveAt")

    bike = get_bike_info(value_line[4])
    user = UserModel(bike)
    user.increase_utility_by_n("time", int(value_line[5]))
    user.increase_utility_by_n("sweat", int(value_line[6]))
    user.increase_utility_by_n("scenery", int(value_line[7]))
    user.increase_utility_by_n("social", int(value_line[8]))

    user.utilities.normalize()
    print("utilities : %s" % user.utilities)

    return {"user" : user, "start" : start, "end" : end, "time_info" : time_info}

def get_bike_info(bike_str):
    if bike_str == "walk":
        return False
    return True

def get_elevation_change(trip, testing=False):
    # TODO: re-implement using the open elevation API
    pass

if __name__ == "__main__":
    main()


from _GLOBAL_OPTIONS_ import factionsOptionMenu, addPremiumItems, addRevive, AddNightmareTickets, removeAds, unlockProfiles
from _PROFILE_OPTIONS_ import addItemsMenu, changeUsername, addCash, setFreeSkillReset, setLevel, setBlackStronboxes, addBlackKeys, addAugmentCores, setSupportItems, addMultiplayerStats
from _UTILS_ import mainTitle
from _EDIT_MANUALLY_ import profileManualEdit
from _SET_PROFILE_PATH_ import setProfilePath
from _FIX_INVENTORY_CRASH_ import fixInventory
from os import _exit, path
from win32console import SetConsoleTitle
from string import ascii_letters
from time import sleep
from json import dump, load
from msvcrt import getch, kbhit
from sys import stdout

mainMenuSelection = ['Global', 'Profile', 'Edit manually', 'Settings', 'About', 'Exit']
configMenuSelection = ['Set Profile', 'Set Profile Path Folder', 'Back up Profile.save [WORK IN PROGRESS]', 'Fix Inventory', 'Back']
globalMenuSelection = ['Factions', 'Premium Items', 'Revive Tokens', 'Premium Nightmare Tickets', 'Remove ads (ADS ON MOBILE)', 'Unlock profile (5-6)', 'Back']
profileMenuSelection = ['Add items', 'Change username', 'Add SAS Cash', 'Set free skill reset', 'Set level', 'Add black Strongboxes', 'Add random Strongboxes [PLACE HOLDER (THIS FEATURE IS WORK IN PROGRESS)]', 'Add black keys', 'Add augment cores', 'Add support items', 'Set stats', 'Back']

def about():
    mainTitle()
    print('''
Developed by: <\\>#0077 | 0daxelagnia

Special thanks to: BlapertureMesa ( cso-idn-player ) and hemisemidemipresent

Official Github repository: https://github.com/0daxelagnia/SAS4Tool/

Latest version: 2.0.0

Made with <3 for the SAS 4 cheats community!

(Press any key to go back)''')
    sleep(0.25)
    while True:
        if kbhit():
            return mainMenu()

def globalMenu():
    SetConsoleTitle('SAS4Tool - Global Menu')
    mainTitle()
    for i in range(len(globalMenuSelection)):
        print(f'[{ascii_letters[26+i]}] - {globalMenuSelection[i]}')
    sleep(0.25)
    while True:
        if kbhit():
            key = getch()
            if key == b'a':
                factionsOptionMenu()
                return mainMenu()
            if key == b'b':
                addPremiumItems()
                return mainMenu()
            if key == b'c':
                addRevive()
                return mainMenu()
            if key == b'd':
                AddNightmareTickets()
                return mainMenu()
            if key == b'e':
                removeAds()
                return mainMenu()
            if key == b'f':
                unlockProfiles()
                return mainMenu()
            if key == b'g':
                return mainMenu()

def profileMenu():
    SetConsoleTitle('SAS4Tool - Profile Menu')
    mainTitle()
    for i in range(len(profileMenuSelection)):
        print(f'[{ascii_letters[26+i]}] - {profileMenuSelection[i]}')
    sleep(0.25)
    while True:
        if kbhit():
            key = getch()
            if key == b'a':
                addItemsMenu()
                return mainMenu()
            if key == b'b':
                changeUsername()
                return mainMenu()
            if key == b'c':
                addCash()
                return mainMenu()
            if key == b'd':
                setFreeSkillReset()
                return mainMenu()
            if key == b'e':
                setLevel()
                return mainMenu()
            if key == b'f':
                setBlackStronboxes()
                return mainMenu()
            if key == b'g':
                pass
            if key == b'h':
                addBlackKeys()
                return mainMenu()
            if key == b'i':
                addAugmentCores()
                return mainMenu()
            if key == b'j':
                setSupportItems()
                return mainMenu()
            if key == b'k':
                addMultiplayerStats()
                return mainMenu()
            if key == b'l':
                return mainMenu()

def setProfileConfig(consoleProfileList):
    SetConsoleTitle('SAS4Tool - Set profile')
    mainTitle()
    print('Select a profile:\n')
    for i in range(len(consoleProfileList)):
        print(f'[{ascii_letters[26+i]}] - {consoleProfileList[i]}')
    sleep(0.25)
    with open('config.json', 'r+') as f:
        data = load(f)
        f.seek(0)
        f.truncate()
        while True:
            if kbhit():
                key = getch()
                if key == b'a':
                    data['consoleDefaultProfile'] = 'Profile 1'
                    data['defaultProfile'] = 'Profile0'
                    dump(data, f)
                    break
                if key == b'b':
                    data['consoleDefaultProfile'] = 'Profile 2'
                    data['defaultProfile'] = 'Profile1'
                    dump(data, f)
                    break
                if key == b'c':
                    data['consoleDefaultProfile'] = 'Profile 3'
                    data['defaultProfile'] = 'Profile2'
                    dump(data, f)
                    break
                if key == b'd':
                    data['consoleDefaultProfile'] = 'Profile 4'
                    data['defaultProfile'] = 'Profile3'
                    dump(data, f)
                    break
                if key == b'e':
                    data['consoleDefaultProfile'] = 'Profile 5'
                    data['defaultProfile'] = 'Profile4'
                    dump(data, f)
                    break
                if key == b'f':
                    data['consoleDefaultProfile'] = 'Profile 6'
                    data['defaultProfile'] = 'Profile5'
                    dump(data, f)
                    break

def configMenu():
    consoleProfileList = ['Profile 1', 'Profile 2', 'Profile 3', 'Profile 4', 'Profile 5', 'Profile 6']
    SetConsoleTitle('SAS4Tool - Config Menu')
    mainTitle()
    for i in range(len(configMenuSelection)):
        print(f'[{ascii_letters[26+i]}] - {configMenuSelection[i]}')
    sleep(0.25)
    while True:
        if kbhit():
            key = getch()
            if key == b'a':
                setProfileConfig(consoleProfileList)
                return mainMenu()
            if key == b'b':
                setProfilePath()
                return mainMenu()
            if key == b'c':
                return mainMenu()
            if key == b'd':
                fixInventory()
                return mainMenu()
            if key == b'e':
                return mainMenu()

def mainMenu():
    SetConsoleTitle('SAS4Tool - Main Menu')
    mainTitle()
    for i in range(len(mainMenuSelection)):
        print(f'[{ascii_letters[26+i]}] - {mainMenuSelection[i]}')
    sleep(0.25)
    while True:
        if kbhit():
            key = getch()
            if key == b'a':
                return globalMenu()
            if key == b'b':
                return profileMenu()
            if key == b'c':
                profileManualEdit()
                return mainMenu()
            if key == b'd':
                configMenu()
                return mainMenu()
            if key == b'e':
                about()
                return mainMenu()
            if key == b'f':
                try:
                    stdout.flush()
                    exit()
                except:
                    stdout.flush()
                    _exit(0)

if __name__ == '__main__':
    contents = {'version': '2.0.0', 'developer': '<\\>#0077', 'defaultProfile': 'Profile0', 'consoleDefaultProfile': 'Profile 1', "profileSavePath": ""}
    if not path.exists('config.json'):
        with open('config.json', 'w') as f:
            f.seek(0)
            f.truncate()
            f = dump(contents, f, indent=4)
    if path.exists('config.json'):
        if path.getsize('config.json') == 0:
            with open('config.json', 'w') as f:
                f.seek(0)
                f.truncate()
                f = dump(contents, f, indent=4)
    mainMenu()


import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import os
import shutil

df = pd.read_csv('../data/speakers_all.csv')
df.drop(columns=['Unnamed: 9', 'Unnamed: 10', 'Unnamed: 11'], inplace=True)
df_full = df[df['file_missing?'] == False]
df_full['sex'] = df_full['sex'].apply(lambda x: 'female' if x == 'famale' else x)

top10languages = df_full['native_language'].value_counts()[:10].index.values

train_set_filenames = []
test_set_filenames = []

for language in top10languages:
    X = df_full[df_full['native_language'] == language]['filename'].values
    y = [language] * len(X)
    X_train, X_test, y_train, y_test = train_test_split(X, y)
    train_set_filenames.append(X_train)
    test_set_filenames.append(X_test)

train_names = []
for lst in train_set_filenames:
    for file in lst:
        train_names.append(file)

test_names = []
for lst in test_set_filenames:
    for file in lst:
        test_names.append(file)

df_full['train_test_none'] = df_full['filename'].apply(lambda x: "train" if x in train_names else "test" if x in test_names else "none")

df_full[df_full['train_test_none'] != 'none'].to_csv("../data/train_test.csv")

current_dir = "../data/recordings/wav_16khz"

for idx, row in df_full.iterrows():
    if row['train_test_none'] == 'none':
        continue
    elif row['train_test_none'] == 'train':
        new_path = os.path.join("../data/recordings/train_set", row['native_language'], row['filename'] + ".wav")
    elif row['train_test_none'] == 'test':
        new_path = os.path.join("../data/recordings/test_set", row['native_language'], row['filename'] + ".wav")
    current_path = os.path.join(current_dir, row['filename'] + ".wav")
    shutil.copyfile(current_path, new_path)


# -*- coding: utf-8 -*-
from __future__ import absolute_import
import json
import logging

from tornado.escape import json_encode
from tornado.escape import json_decode
from tornado.escape import utf8

from .constant import *

logger = logging.getLogger('server.' + __name__)

class JsonStream:

    def __init__(self, stream, address):
        self._stream = stream
        self._address = address
        self._stream.read_until(bDELIMITER, self.on_read)

    async def on_read(self, data):
        try:
            if data:
                dict_ = json_decode(data)
            await self.on_read_json(dict_)
        except Exception as e:
            logger.error('Error occurs during decoding data from device.\n\
                          {}'.format(e), exc_info=True)
        self._stream.read_until(bDELIMITER, self.on_read)

    def on_read_json(self, dict_):
        pass

    def send_json(self, dict_):
        if not self._stream.closed():
            self._stream.write(utf8(json_encode(dict_) + DELIMITER))


#!/home/meichen/anaconda3/bin/python

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os
import glob
import matplotlib.ticker as mticker
from matplotlib.ticker import StrMethodFormatter, NullFormatter

def main():
    data = pd.read_csv('pairsfile_rgp_select.csv',skipinitialspace=True)
    data_array = np.array(data)
    jpath = '/home/meichen/work1/SR_Attn/pair_events'
    phase = 'P'
    distance = '85'

    pairs = {}
    masterid = []
    numberid = []
    for i in np.arange(len(data_array[:,0])):
        if data_array[i,0] not in pairs.keys():
            masterid.append(data_array[i,0])
            numberid.append(data_array[i,19])
        pairs.setdefault(data_array[i,0],[]).append(data_array[i,6])

    for key in list(pairs.keys()):
        index=list(data_array[:,0]).index(key)
        os.chdir('{}/master_{}'.format(jpath,key))
        num = 0
        fig = plt.figure(figsize=[4,2])
        ax1 = fig.add_subplot(111)

        for value in list(pairs.get(key)):
            stn_num = glob.glob('egf_{}/{}/gcarc_{}/all*'.format(value,phase,distance))[0].split('.')[7]
            d = np.genfromtxt('{}'.format(glob.glob('egf_{}/{}/gcarc_{}/all*'.format(value,phase,distance))[0]))
            d = d[d[:,0]<2.0]
            indices = [l for l,x in enumerate(data_array[:,0]) if x == key]
            index = list(data_array[l,6] for l in indices).index(value)
            fc = data_array[indices[0]+index,17]
            a = data_array[indices[0]+index,15]
            b = data_array[indices[0]+index,16]

            ax1.loglog(d[:,0],d[:,1],'C{}'.format(num),label='{} stn:{}'.format(value,stn_num),lw=0.5,alpha=0.75)
            ax1.loglog(d[:,0],func_Boatwright(d[:,0],a,b,fc),linestyle='--',color='grey',lw=1)
            ax1.plot(fc,func_Boatwright(fc,a,b,fc),marker='v',markeredgecolor='C{}'.format(num),markerfacecolor='C{}'.format(num),linewidth=2)
            num = num + 1
            num = num % 9
        ax1.set_xlabel('Frequency (Hz)',size=8)
        ax1.set_ylabel('Spectral ratios',size=8)
        ax1.set_xticks([0.025,0.1,1,2])
        ax1.set_xticklabels([0.025,0.1,1,2])
        ax1.yaxis.set_major_locator(mticker.LogLocator(subs=(0.3,1.0,)))
        ax1.yaxis.set_major_formatter(mticker.ScalarFormatter())
        ax1.yaxis.set_minor_formatter(mticker.NullFormatter())
        ax1.tick_params(axis='both',which='both',labelsize=6)
        print(key,phase,distance)
        n = masterid.index(key)
        ax1.set_title('# {}'.format(numberid[n]),size=10)
        fig.tight_layout()
        plt.savefig('/home/meichen/Research/SR_Attn/pair_events/figures/master_{}.pdf'.format(numberid[n]))
        plt.close()

def func(x,a,b,c):
    return a * (1 + x**2 / b**2)/(1 + x**2 / c**2)

def func_Boatwright(x,a,b,c):
    return a * (1 + x**4/ b**4)**0.5 / (1+x**4/c**4)**0.5

main()


from ..h2o import random_forest
from .estimator_base import H2OEstimator

class H2ORandomForestEstimator(H2OEstimator):
  def __init__(self,mtries=None,sample_rate=None,build_tree_one_node=None,ntrees=None,
               max_depth=None,min_rows=None,nbins=None,nbins_cats=None,
               binomial_double_trees=None,balance_classes=None,max_after_balance_size=None,
               seed=None,offset_column=None,weights_column=None):
    super(H2ORandomForestEstimator, self).__init__()
    self.parms = locals()
    self.parms = {k:v for k,v in self.parms.iteritems() if k!="self"}
    self._estimator_type="regressor"

  def fit(self,X,y=None,**params):
    if y is not None:
      if y.isfactor(): self._estimator_type="classifier"
    self.__dict__=random_forest(x=X,y=y,**self.parms).__dict__.copy()


import os
import allure
import pytest
import logging
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
import allure
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options

class BasePage:
    def __init__(self, driver):
        self.driver = driver

    @allure.step("Проверка URL: {expected_url}")
    def check_url(self, expected_url):
        assert self.driver.current_url == expected_url
        logging.info(
            f"Проверка URL: Ожидаемый URL - {expected_url}, "
            f"текущий URL - {self.driver.current_url}"
        )

class SbisHomePage(BasePage):
    URL = "https://sbis.ru/"

    @allure.step("Переход в раздел 'Контакты'.")
    def go_to_contacts(self):
        header_menu = self.driver.find_element(
            By.CLASS_NAME,
            "sbisru-Header__menu.ws-flexbox.ws-align-items-center"
        )
        contacts_link = header_menu.find_element(By.LINK_TEXT, "Контакты")
        contacts_link.click()
        logging.info("Переход на страницу 'Контакты' выполнен.")

@pytest.fixture
def browser():
    download_folder = os.path.join(os.path.dirname(__file__), 'downloads')

    chrome_options = Options()
    chrome_options.add_experimental_option('prefs', {
        'download.default_directory': download_folder,
        'download.prompt_for_download': False,
        'download.directory_upgrade': True,
        'safebrowsing.enabled': False,
        'profile.default_content_settings.popups': 0
    })
    chrome_options.add_argument('--disable-notifications')
    chrome_options.add_argument('--disable-infobars')
    chrome_options.add_argument('--disable-software-rasterizer')
    chrome_options.add_argument('--safebrowsing-disable-download-protection')
    chrome_options.add_argument('--disable-web-security')

    driver = webdriver.Chrome(options=chrome_options)
    yield driver
    driver.quit()

def close_cookie_message(driver, class_name):
    try:
        close_cookie_message = driver.find_element(By.CLASS_NAME, class_name)
        if close_cookie_message.is_displayed():
            close_cookie_message.click()
        logging.info("Закрытие сообщения о куки выполнено.")
    except NoSuchElementException:
        pass


import ismrmrd
import os
import itertools
import logging
import numpy as np
import numpy.fft as fft
import ctypes
import mrdhelper
from datetime import datetime

# Folder for debug output files
debugFolder = "/tmp/share/debug"

def groups(iterable, predicate):
    group = []
    for item in iterable:
        group.append(item)

        if predicate(item):
            yield group
            group = []

def conditionalGroups(iterable, predicateAccept, predicateFinish):
    group = []
    try:
        for item in iterable:
            if item is None:
                break

            if predicateAccept(item):
                group.append(item)

            if predicateFinish(item):
                yield group
                group = []
    finally:
        iterable.send_close()

def process(connection, config, metadata):
    logging.info("Config: \n%s", config)
    logging.info("Metadata: \n%s", metadata)

    # Discard phase correction lines and accumulate lines until "ACQ_LAST_IN_SLICE" is set
    for group in conditionalGroups(connection, lambda acq: not acq.is_flag_set(ismrmrd.ACQ_IS_PHASECORR_DATA), lambda acq: acq.is_flag_set(ismrmrd.ACQ_LAST_IN_SLICE)):
        image = process_group(group, config, metadata)

        logging.debug("Sending image to client:\n%s", image)
        connection.send_image(image)

def process_group(group, config, metadata):
    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder + " for debug output files")

    # Format data into single [cha RO PE] array
    data = [acquisition.data for acquisition in group]
    data = np.stack(data, axis=-1)

    logging.debug("Raw data is size %s" % (data.shape,))
    np.save(debugFolder + "/" + "raw.npy", data)

    # Fourier Transform
    data = fft.fftshift(data, axes=(1, 2))
    data = fft.ifft2(data)
    data = fft.ifftshift(data, axes=(1, 2))

    # Sum of squares coil combination
    data = np.abs(data)
    data = np.square(data)
    data = np.sum(data, axis=0)
    data = np.sqrt(data)

    logging.debug("Image data is size %s" % (data.shape,))
    np.save(debugFolder + "/" + "img.npy", data)

    # Normalize and convert to int16
    data *= 32767/data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Remove phase oversampling
    nRO = np.size(data,0)
    data = data[int(nRO/4):int(nRO*3/4),:]
    logging.debug("Image without oversampling is size %s" % (data.shape,))
    np.save(debugFolder + "/" + "imgCrop.npy", data)

    # Format as ISMRMRD image data
    image = ismrmrd.Image.from_array(data, acquisition=group[0])
    image.image_index = 1

    # Set field of view
    image.field_of_view = (ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.x),
                            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.y),
                            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.z))

    # Set ISMRMRD Meta Attributes
    meta = ismrmrd.Meta({'DataRole':               'Image',
                         'ImageProcessingHistory': ['FIRE', 'PYTHON'],
                         'WindowCenter':           '16384',
                         'WindowWidth':            '32768'})

    # Add image orientation directions to MetaAttributes if not already present
    if meta.get('ImageRowDir') is None:
        meta['ImageRowDir'] = ["{:.18f}".format(image.getHead().read_dir[0]), "{:.18f}".format(image.getHead().read_dir[1]), "{:.18f}".format(image.getHead().read_dir[2])]

    if meta.get('ImageColumnDir') is None:
        meta['ImageColumnDir'] = ["{:.18f}".format(image.getHead().phase_dir[0]), "{:.18f}".format(image.getHead().phase_dir[1]), "{:.18f}".format(image.getHead().phase_dir[2])]

    xml = meta.serialize()
    logging.debug("Image MetaAttributes: %s", xml)
    logging.debug("Image data has %d elements", image.data.size)

    image.attribute_string = xml
    return image


from django.urls import path
from .import views

urlpatterns = [
    path("", views.index, name="storehome"),
    path("about/", views.about, name="aboutus"),
    path("contact/", views.contact, name="contactus"),
    path("Seller/", views.seller, name="sellerid"),                  #Seller/ is the html file name not the function name
    path("search/", views.search, name="searchbar"),
    path("productview/<int:getid>", views.prodView, name="productview1"),
    path("checkout/", views.checkout, name="checkout"),
    path("signup/", views.signup, name="signup"),
path("handlelogin/", views.handlelogin, name="handlelogin"),
path("handlelogout/", views.handlelogout, name="handlelogout")

]


import imp
import importlib
import inspect
import os
import sys
import weakref
from collections import namedtuple
from enum import Enum

from dagster import check
from dagster.core.definitions.partition import RepositoryPartitionsHandle
from dagster.core.definitions.pipeline import PipelineDefinition
from dagster.core.definitions.repository import RepositoryDefinition
from dagster.core.errors import DagsterInvariantViolationError
from dagster.core.scheduler import SchedulerHandle
from dagster.utils import load_yaml_from_path

if sys.version_info > (3,):
    from pathlib import Path  # pylint: disable=import-error
else:
    from pathlib2 import Path  # pylint: disable=import-error

EPHEMERAL_NAME = '<<unnamed>>'

class PartitionLoaderEntrypoint(
    namedtuple('_PartitionLoaderEntrypoint', 'module module_name fn_name from_handle')
):
    def __new__(cls, module, module_name, fn_name, from_handle=None):
        return super(PartitionLoaderEntrypoint, cls).__new__(
            cls, module, module_name, fn_name, from_handle
        )

    def perform_load(self):
        # in the decorator case the attribute will be the actual definition
        if not hasattr(self.module, self.fn_name):
            raise DagsterInvariantViolationError(
                '{name} not found in module {module}.'.format(name=self.fn_name, module=self.module)
            )

        fn_partitions = getattr(self.module, self.fn_name)

        if isinstance(fn_partitions, RepositoryPartitionsHandle):
            inst = fn_partitions
        elif callable(fn_partitions):
            handle = fn_partitions()

            if not isinstance(handle, RepositoryPartitionsHandle):
                raise DagsterInvariantViolationError(
                    '{fn_name} is a function but must return a RepositoryPartitionsHandle.'.format(
                        fn_name=self.fn_name
                    )
                )

            inst = handle

        else:
            raise DagsterInvariantViolationError(
                '{fn_name} must be a function that returns a RepositoryPartitionstHandle.'.format(
                    fn_name=self.fn_name
                )
            )

        return inst

    @staticmethod
    def from_file_target(python_file, fn_name, from_handle=None):
        file_directory = os.path.dirname(python_file)
        if file_directory not in sys.path:
            sys.path.append(file_directory)

        module_name = os.path.splitext(os.path.basename(python_file))[0]
        module = imp.load_source(module_name, python_file)

        return PartitionLoaderEntrypoint(module, module_name, fn_name, from_handle)

    @staticmethod
    def from_module_target(module_name, fn_name, from_handle=None):
        module = importlib.import_module(module_name)
        return PartitionLoaderEntrypoint(module, module_name, fn_name, from_handle)

    @staticmethod
    def from_yaml(file_path, from_handle=None):
        check.str_param(file_path, 'file_path')

        config = load_yaml_from_path(file_path)
        if not config.get('partitions'):
            return None

        partitions = check.dict_elem(config, 'partitions')
        module_name = check.opt_str_elem(partitions, 'module')
        file_name = check.opt_str_elem(partitions, 'file')
        fn_name = check.str_elem(partitions, 'fn')

        if module_name:
            return PartitionLoaderEntrypoint.from_module_target(module_name, fn_name, from_handle)
        else:
            # rebase file in config off of the path in the config file
            file_name = os.path.join(os.path.dirname(os.path.abspath(file_path)), file_name)
            return PartitionLoaderEntrypoint.from_file_target(file_name, fn_name, from_handle)

class SchedulerLoaderEntrypoint(
    namedtuple('_SchedulerLoaderEntrypoint', 'module module_name fn_name from_handle')
):
    def __new__(cls, module, module_name, fn_name, from_handle=None):
        return super(SchedulerLoaderEntrypoint, cls).__new__(
            cls, module, module_name, fn_name, from_handle
        )

    def perform_load(self, artifacts_dir):
        artifacts_dir = check.str_param(artifacts_dir, 'artifacts_dir')
        repository_name = self.from_handle.build_repository_definition().name

        # in the decorator case the attribute will be the actual definition
        if not hasattr(self.module, self.fn_name):
            raise DagsterInvariantViolationError(
                '{name} not found in module {module}.'.format(name=self.fn_name, module=self.module)
            )

        fn_scheduler = getattr(self.module, self.fn_name)

        if callable(fn_scheduler):
            scheduler = fn_scheduler(artifacts_dir=artifacts_dir, repository_name=repository_name)

            if not isinstance(scheduler, SchedulerHandle):
                raise DagsterInvariantViolationError(
                    '{fn_name} is a function but must return a SchedulerHandle.'.format(
                        fn_name=self.fn_name
                    )
                )

            inst = scheduler

        else:
            raise DagsterInvariantViolationError(
                '{fn_name} must be a function that returns a SchedulerHandle.'.format(
                    fn_name=self.fn_name
                )
            )

        return inst

    @staticmethod
    def from_file_target(python_file, fn_name, from_handle=None):
        file_directory = os.path.dirname(python_file)
        if file_directory not in sys.path:
            sys.path.append(file_directory)

        module_name = os.path.splitext(os.path.basename(python_file))[0]
        module = imp.load_source(module_name, python_file)

        return SchedulerLoaderEntrypoint(module, module_name, fn_name, from_handle)

    @staticmethod
    def from_module_target(module_name, fn_name, from_handle=None):
        module = importlib.import_module(module_name)
        return SchedulerLoaderEntrypoint(module, module_name, fn_name, from_handle)

    @staticmethod
    def from_yaml(file_path, from_handle=None):
        check.str_param(file_path, 'file_path')

        config = load_yaml_from_path(file_path)
        if not config.get('scheduler'):
            return None

        scheduler = check.dict_elem(config, 'scheduler')
        module_name = check.opt_str_elem(scheduler, 'module')
        file_name = check.opt_str_elem(scheduler, 'file')
        fn_name = check.str_elem(scheduler, 'fn')

        if module_name:
            return SchedulerLoaderEntrypoint.from_module_target(module_name, fn_name, from_handle)
        else:
            # rebase file in config off of the path in the config file
            file_name = os.path.join(os.path.dirname(os.path.abspath(file_path)), file_name)
            return SchedulerLoaderEntrypoint.from_file_target(file_name, fn_name, from_handle)

class LoaderEntrypoint(namedtuple('_LoaderEntrypoint', 'module module_name fn_name from_handle')):
    def __new__(cls, module, module_name, fn_name, from_handle=None):
        return super(LoaderEntrypoint, cls).__new__(cls, module, module_name, fn_name, from_handle)

    def perform_load(self):
        # in the decorator case the attribute will be the actual definition
        if not hasattr(self.module, self.fn_name):
            raise DagsterInvariantViolationError(
                '{name} not found in module {module}.'.format(name=self.fn_name, module=self.module)
            )

        fn_repo_or_pipeline = getattr(self.module, self.fn_name)

        # This is the @pipeline case
        if isinstance(fn_repo_or_pipeline, PipelineDefinition):
            inst = fn_repo_or_pipeline

        # This is the define_pipeline() or define_repo() case
        elif callable(fn_repo_or_pipeline):
            repo_or_pipeline = fn_repo_or_pipeline()

            if not isinstance(repo_or_pipeline, (RepositoryDefinition, PipelineDefinition)):
                raise DagsterInvariantViolationError(
                    '{fn_name} is a function but must return a PipelineDefinition '
                    'or a RepositoryDefinition, or be decorated with @pipeline.'.format(
                        fn_name=self.fn_name
                    )
                )

            inst = repo_or_pipeline

        else:
            raise DagsterInvariantViolationError(
                '{fn_name} must be a function that returns a PipelineDefinition '
                'or a RepositoryDefinition, or a function decorated with @pipeline.'.format(
                    fn_name=self.fn_name
                )
            )

        if self.from_handle:
            return ExecutionTargetHandle.cache_handle(inst, self.from_handle)

        return inst

    @staticmethod
    def from_file_target(python_file, fn_name, from_handle=None):
        file_directory = os.path.dirname(python_file)
        if file_directory not in sys.path:
            sys.path.append(file_directory)

        module_name = os.path.splitext(os.path.basename(python_file))[0]
        module = imp.load_source(module_name, python_file)

        return LoaderEntrypoint(module, module_name, fn_name, from_handle)

    @staticmethod
    def from_module_target(module_name, fn_name, from_handle=None):
        module = importlib.import_module(module_name)
        return LoaderEntrypoint(module, module_name, fn_name, from_handle)

    @staticmethod
    def from_yaml(file_path, from_handle=None):
        check.str_param(file_path, 'file_path')

        config = load_yaml_from_path(file_path)
        repository_config = check.dict_elem(config, 'repository')
        module_name = check.opt_str_elem(repository_config, 'module')
        file_name = check.opt_str_elem(repository_config, 'file')
        fn_name = check.str_elem(repository_config, 'fn')

        if module_name:
            return LoaderEntrypoint.from_module_target(module_name, fn_name, from_handle)
        else:
            # rebase file in config off of the path in the config file
            file_name = os.path.join(os.path.dirname(os.path.abspath(file_path)), file_name)
            return LoaderEntrypoint.from_file_target(file_name, fn_name, from_handle)

class ExecutionTargetHandleCacheEntry(
    namedtuple('_ExecutionTargetHandleCacheEntry', 'handle solid_subset')
):
    def __new__(cls, handle, solid_subset=None):
        check.inst_param(handle, 'handle', ExecutionTargetHandle)
        check.opt_list_param(solid_subset, 'solid_subset', of_type=str)
        return super(ExecutionTargetHandleCacheEntry, cls).__new__(cls, handle, solid_subset)

class ExecutionTargetHandle(object):
    '''ExecutionTargetHandle represents an immutable, serializable reference to a Dagster
    RepositoryDefinition or PipelineDefinition, to support dynamically loading these in various
    contexts (e.g. across process boundaries).

    This class must remain pickle-serializable to ensure multiprocessing compatibility, and is the
    one of the primary reasons that we pass this around vs. an instantiated
    RepositoryDefinition/PipelineDefinition object.

    ### Creation
    ExecutionTargetHandles can be created via the staticmethod constructors below.

        - for_repo_fn
        - for_repo_yaml
        - for_repo_python_file
        - for_repo_module
        - for_pipeline_fn
        - for_pipeline_python_file
        - for_pipeline_module

    Also, the following constructors are provided to support construction from CLI tools in
    dagster.cli.load_handle:

        - handle_for_repo_cli_args
        - handle_for_pipeline_cli_args

    Since an ExecutionTargetHandle can reference either a RepositoryDefinition or a fully-qualified
    pipeline, it provides a property `is_resolved_to_pipeline` which identifies whether it is fully-
    qualified to a pipeline reference.

    For repository-based handles, you can use the `with_pipeline_name(pipeline_name)` method on a
    repository handle to construct and return a new fully-qualified pipeline handle.

    ### Usage
    Handle objects support the following methods to construct `*Definition` objects:

        - handle.build_repository_definition() => RepositoryDefinition
        - handle.build_pipeline_definition() => PipelineDefinition

    These are intended to support reconstructing definitions from their serialized representations
    provided by this object wherever needed during execution.

    The first is supported on all handles; the second requires a fully-qualified pipeline handle.
    For more advanced usage, you can also construct an entrypoint object yourself with:

        - handle.entrypoint() => LoaderEntrypoint

    This should not be necessary in common usage.
    '''

    __cache__ = weakref.WeakKeyDictionary()
    '''The cache is used to cache handles used to create PipelineDefinition and
    RepositoryDefinition objects, so the handles can be passed across serialization boundaries (as
    for dagstermill) by solid compute logic.'''

    @classmethod
    def get_handle(cls, repo_or_pipeline):
        '''Get the handle and, optionally, solid subset used to construct a repo or (sub-)pipeline.

        Returns: Union[ExecutionTargetHandleCacheEntry, (None, None)]
        '''
        check.inst_param(
            repo_or_pipeline, 'repo_or_pipeline', (RepositoryDefinition, PipelineDefinition)
        )
        return cls.__cache__.get(repo_or_pipeline) or (None, None)

    @classmethod
    def cache_handle(cls, repo_or_pipeline_def, handle=None, solid_names=None):
        '''Record a pipeline or repository in the cache.

        Args:
            repo_or_pipeline_def (Union[RepositoryDefinition, PipelineDefinition]): The repo or
                pipeline definition for which to cache the handle.

        Kwargs:
            handle (ExecutionTargetHandle): The handle to cache.
            solid_names (Optional[List[str]]): The solid names constituting the constructed
                sub-pipeline, if any; arg should be as for
                dagster.core.definitions.pipeline.build_sub_pipeline.
        '''
        check.inst_param(
            repo_or_pipeline_def, 'repo_or_pipeline_def', (RepositoryDefinition, PipelineDefinition)
        )
        check.inst_param(handle, 'handle', ExecutionTargetHandle)
        check.opt_list_param(solid_names, 'solid_names', of_type=str)
        cls.__cache__[repo_or_pipeline_def] = ExecutionTargetHandleCacheEntry(handle, solid_names)

        return repo_or_pipeline_def

    @staticmethod
    def for_pipeline_fn(fn):
        '''This builder is a bit magical, but it inspects its caller to determine how to build a
        ExecutionTargetHandle object via python_file and fn_name.

        This will work since fn_name is ensured to be in scope in the python_file caller's scope.
        '''
        check.callable_param(fn, 'fn')
        return ExecutionTargetHandle.for_pipeline_python_file(
            python_file=_get_python_file_from_previous_stack_frame(), fn_name=fn.__name__
        )

    @staticmethod
    def for_repo_fn(fn):
        '''This builder is a bit magical, but it inspects its caller to determine how to build a
        ExecutionTargetHandle object via python_file and fn_name.

        This will work since fn_name is ensured to be in scope in the python_file caller's scope.
        '''
        check.callable_param(fn, 'fn')
        return ExecutionTargetHandle.for_repo_python_file(
            python_file=_get_python_file_from_previous_stack_frame(), fn_name=fn.__name__
        )

    @staticmethod
    def for_repo_yaml(repository_yaml):
        '''Builds an ExecutionTargetHandle for a repository.yml file.
        '''
        return ExecutionTargetHandle(
            _ExecutionTargetHandleData(repository_yaml=os.path.abspath(repository_yaml)),
            _ExecutionTargetMode.REPOSITORY,
        )

    @staticmethod
    def for_repo_python_file(python_file, fn_name):
        '''Builds an ExecutionTargetHandle for a repository python file and function which is
        expected to return a RepositoryDefinition instance.
        '''
        return ExecutionTargetHandle(
            _ExecutionTargetHandleData(python_file=python_file, fn_name=fn_name),
            _ExecutionTargetMode.REPOSITORY,
        )

    @staticmethod
    def for_repo_module(module_name, fn_name):
        '''Builds an ExecutionTargetHandle for a repository module and function which is expected
        to return a RepositoryDefinition instance.
        '''
        return ExecutionTargetHandle(
            _ExecutionTargetHandleData(module_name=module_name, fn_name=fn_name),
            _ExecutionTargetMode.REPOSITORY,
        )

    @staticmethod
    def for_pipeline_python_file(python_file, fn_name):
        '''Builds an ExecutionTargetHandle for a pipeline python file and function which is expected
        to return a PipelineDefinition instance.
        '''
        return ExecutionTargetHandle(
            _ExecutionTargetHandleData(python_file=python_file, fn_name=fn_name),
            _ExecutionTargetMode.PIPELINE,
            is_resolved_to_pipeline=True,
        )

    @staticmethod
    def for_pipeline_module(module_name, fn_name):
        '''Builds an ExecutionTargetHandle for a pipeline python module and function which is
        expected to return a PipelineDefinition instance.
        '''
        return ExecutionTargetHandle(
            _ExecutionTargetHandleData(module_name=module_name, fn_name=fn_name),
            _ExecutionTargetMode.PIPELINE,
            is_resolved_to_pipeline=True,
        )

    @staticmethod
    def from_dict(handle_dict):
        return ExecutionTargetHandle(
            data=_ExecutionTargetHandleData(**handle_dict['data']),
            mode=getattr(_ExecutionTargetMode, handle_dict['mode']),
            is_resolved_to_pipeline=handle_dict['is_resolved_to_pipeline'],
        )

    def to_dict(self):
        return {
            'data': self.data._asdict(),
            'mode': self.mode.name,
            'is_resolved_to_pipeline': self.is_resolved_to_pipeline,
        }

    def with_pipeline_name(self, pipeline_name):
        '''Returns a new ExecutionTargetHandle that references the pipeline "pipeline_name" within
        the repository.
        '''
        if self.is_resolved_to_pipeline and self.data.pipeline_name == pipeline_name:
            return self

        check.invariant(
            not (self.is_resolved_to_pipeline and self.data.pipeline_name is not None),
            '''ExecutionTargetHandle already references a pipeline named {pipeline_name}, cannot
            change to {new_pipeline_name}.'''.format(
                pipeline_name=self.data.pipeline_name, new_pipeline_name=pipeline_name
            ),
        )
        data = self.data._replace(pipeline_name=pipeline_name)
        return ExecutionTargetHandle(
            data, mode=_ExecutionTargetMode.PIPELINE, is_resolved_to_pipeline=True
        )

    def build_scheduler_handle(self, artifacts_dir):
        # Cannot create a scheduler handle if the target mode is not a repository
        if self.mode != _ExecutionTargetMode.REPOSITORY:
            return None

        entrypoint = self.scheduler_handle_entrypoint
        # entrypoint will be None if the repository yaml file does not define a scheduler entrypoint
        if not entrypoint:
            return None

        return self.scheduler_handle_entrypoint.perform_load(artifacts_dir)

    def build_partitions_handle(self):
        if self.mode != _ExecutionTargetMode.REPOSITORY:
            return None

        entrypoint = self.partition_handle_entrypoint

        if not entrypoint:
            return None

        return self.partition_handle_entrypoint.perform_load()

    def build_repository_definition(self):
        '''Rehydrates a RepositoryDefinition from an ExecutionTargetHandle object.

        If this ExecutionTargetHandle points to a pipeline, we create an ephemeral repository to
        wrap the pipeline and return it.
        '''
        obj = self.entrypoint.perform_load()

        if self.mode == _ExecutionTargetMode.REPOSITORY:
            # User passed in a function that returns a pipeline definition, not a repository. See:
            # https://github.com/dagster-io/dagster/issues/1439
            if isinstance(obj, PipelineDefinition):
                return ExecutionTargetHandle.cache_handle(
                    RepositoryDefinition(name=EPHEMERAL_NAME, pipeline_defs=[obj]),
                    *ExecutionTargetHandle.get_handle(obj)
                )
            return ExecutionTargetHandle.cache_handle(check.inst(obj, RepositoryDefinition), self)
        elif self.mode == _ExecutionTargetMode.PIPELINE:
            # This handle may have originally targeted a repository and then been qualified with
            # with_pipeline_name()
            if isinstance(obj, RepositoryDefinition):
                return ExecutionTargetHandle.cache_handle(
                    obj, *ExecutionTargetHandle.get_handle(obj)
                )

            return ExecutionTargetHandle.cache_handle(
                RepositoryDefinition(name=EPHEMERAL_NAME, pipeline_defs=[obj]),
                *ExecutionTargetHandle.get_handle(obj)
            )
        else:
            check.failed('Unhandled mode {mode}'.format(mode=self.mode))

    def build_pipeline_definition(self):
        '''Rehydrates a PipelineDefinition from an ExecutionTargetHandle object.
        '''
        if self.mode == _ExecutionTargetMode.REPOSITORY:
            raise DagsterInvariantViolationError(
                'Cannot construct a pipeline from a repository-based ExecutionTargetHandle without'
                ' a pipeline name. Use with_pipeline_name() to construct a pipeline'
                ' ExecutionTargetHandle.'
            )
        elif self.mode == _ExecutionTargetMode.PIPELINE:
            obj = self.entrypoint.perform_load()
            if isinstance(obj, PipelineDefinition):
                return ExecutionTargetHandle.cache_handle(obj, self)
            else:
                return ExecutionTargetHandle.cache_handle(
                    obj.get_pipeline(self.data.pipeline_name), self
                )
        else:
            check.failed('Unhandled mode {mode}'.format(mode=self.mode))

    @property
    def partition_handle_entrypoint(self):
        return self.data.get_partition_entrypoint(from_handle=self)

    @property
    def scheduler_handle_entrypoint(self):
        return self.data.get_scheduler_entrypoint(from_handle=self)

    @property
    def entrypoint(self):
        if self.mode == _ExecutionTargetMode.REPOSITORY:
            return self.data.get_repository_entrypoint(from_handle=self)
        elif self.mode == _ExecutionTargetMode.PIPELINE:
            return self.data.get_pipeline_entrypoint(from_handle=self)
        else:
            check.failed('Unhandled mode {mode}'.format(mode=self.mode))

    def __init__(self, data, mode, is_resolved_to_pipeline=False):
        '''Not intended to be invoked directly. Use one of the factory functions above.
        '''
        self.data = check.inst_param(data, 'data', _ExecutionTargetHandleData)
        self.mode = check.inst_param(mode, 'mode', _ExecutionTargetMode)

        # By default, this only resolves to a repository
        self.is_resolved_to_pipeline = is_resolved_to_pipeline

def _get_python_file_from_previous_stack_frame():
    '''inspect.stack() lets us introspect the call stack; inspect.stack()[1] is the previous
    stack frame.

    In Python < 3.5, this is just a tuple, of which the python file of the previous frame is the 1st
    element.

    In Python 3.5+, this is a FrameInfo namedtuple instance; the python file of the previous frame
    remains the 1st element.
    '''

    # Since this is now a function in this file, we need to go back two hops to find the
    # callsite file.
    previous_stack_frame = inspect.stack()[2]

    # See: https://docs.python.org/3/library/inspect.html
    if sys.version_info.major == 3 and sys.version_info.minor >= 5:
        check.inst(previous_stack_frame, inspect.FrameInfo)
    else:
        check.inst(previous_stack_frame, tuple)

    python_file = previous_stack_frame[1]
    return os.path.abspath(python_file)

class _ExecutionTargetMode(Enum):
    PIPELINE = 1
    REPOSITORY = 2

class _ExecutionTargetHandleData(
    namedtuple(
        '_ExecutionTargetHandleData',
        'repository_yaml module_name python_file fn_name pipeline_name',
    )
):
    def __new__(
        cls,
        repository_yaml=None,
        module_name=None,
        python_file=None,
        fn_name=None,
        pipeline_name=None,
    ):
        return super(_ExecutionTargetHandleData, cls).__new__(
            cls,
            repository_yaml=check.opt_str_param(repository_yaml, 'repository_yaml'),
            module_name=check.opt_str_param(module_name, 'module_name'),
            python_file=check.opt_str_param(python_file, 'python_file'),
            fn_name=check.opt_str_param(fn_name, 'fn_name'),
            pipeline_name=check.opt_str_param(pipeline_name, 'pipeline_name'),
        )

    def get_partition_entrypoint(self, from_handle=None):
        if self.repository_yaml:
            return PartitionLoaderEntrypoint.from_yaml(
                self.repository_yaml, from_handle=from_handle
            )

    def get_scheduler_entrypoint(self, from_handle=None):
        if self.repository_yaml:
            return SchedulerLoaderEntrypoint.from_yaml(
                self.repository_yaml, from_handle=from_handle
            )

    def get_repository_entrypoint(self, from_handle=None):
        if self.repository_yaml:
            return LoaderEntrypoint.from_yaml(self.repository_yaml, from_handle=from_handle)
        elif self.module_name and self.fn_name:
            return LoaderEntrypoint.from_module_target(
                module_name=self.module_name, fn_name=self.fn_name, from_handle=from_handle
            )
        elif self.python_file and self.fn_name:
            return LoaderEntrypoint.from_file_target(
                python_file=self.python_file, fn_name=self.fn_name, from_handle=from_handle
            )
        else:
            raise DagsterInvariantViolationError(
                (
                    'You have attempted to load a repository with an invalid '
                    'combination of properties. repository_yaml {repository_yaml} '
                    'module_name {module_name} python_file {python_file} '
                    'fn_name {fn_name}.'
                ).format(
                    repository_yaml=self.repository_yaml,
                    module_name=self.module_name,
                    fn_name=self.fn_name,
                    python_file=self.python_file,
                )
            )

    def get_pipeline_entrypoint(self, from_handle=None):
        if self.python_file and self.fn_name:
            return LoaderEntrypoint.from_file_target(
                python_file=self.python_file, fn_name=self.fn_name, from_handle=from_handle
            )
        elif self.module_name and self.fn_name:
            return LoaderEntrypoint.from_module_target(
                module_name=self.module_name, fn_name=self.fn_name, from_handle=from_handle
            )
        elif self.pipeline_name:
            return self.get_repository_entrypoint(from_handle=from_handle)
        raise DagsterInvariantViolationError(
            (
                'You have attempted to directly load a pipeline with an invalid '
                'combination of properties module_name {module_name} python_file '
                '{python_file} fn_name {fn_name}.'
            ).format(
                module_name=self.module_name, fn_name=self.fn_name, python_file=self.python_file
            )
        )

    def _asdict(self):
        ddict = super(_ExecutionTargetHandleData, self)._asdict()

        # Normalize to Posix paths
        for key in ['repository_yaml', 'python_file']:
            if ddict[key]:
                ddict[key] = Path(ddict[key]).as_posix()
        return ddict