<commit_before># coding: utf-8

""" Test action-angle stuff """

from __future__ import division, print_function

__author__ = "adrn <adrn@astro.columbia.edu>"

# Standard library
import os, sys
import logging

# Third-party
import matplotlib.pyplot as plt
import numpy as np
from astropy import log as logger
import astropy.units as u

# Project
from ...integrate import LeapfrogIntegrator
from ...potential.lm10 import LM10Potential
from ..actionangle import *

logger.setLevel(logging.DEBUG)

plot_path = "plots/tests/dynamics/actionangle"
if not os.path.exists(plot_path):
    os.makedirs(plot_path)

# HACK:
sys.path.append("/Users/adrian/Downloads/genfunc-master")
import genfunc_3d

def angmom(x):
    return np.array([x[1]*x[5]-x[2]*x[4],x[2]*x[3]-x[0]*x[5],x[0]*x[4]-x[1]*x[3]])

def sanders_classify(X):
    L=angmom(X[0])
    loop = np.array([1,1,1])
    for i in X[1:]:
        L0 = angmom(i)
        if(L0[0]*L[0]<0.):
            loop[0] = 0
        if(L0[1]*L[1]<0.):
            loop[1] = 0
        if(L0[2]*L[2]<0.):
            loop[2] = 0
    return loop

def test_classify():
    usys = (u.kpc, u.Msun, u.Myr)
    potential = NFWPotential(v_h=(121.858*u.km/u.s).decompose(usys).value,
                             r_h=20., q1=0.86, q2=1., q3=1.18, usys=usys)
    acc = lambda t,x: potential.acceleration(x)
    integrator = LeapfrogIntegrator(acc)

    # initial conditions
    loop_w0 = [[6.975016793191392, -93.85342183505938, -71.90978460109265, -0.19151220547102255, -0.5944685489722188, 0.4262481187389783], [-119.85377948180077, -50.68671610744867, -10.05148560039928, -0.3351091185863992, -0.42681239582943836, -0.2512200315205476]]
    t,loop_ws = integrator.run(loop_w0, dt=1., nsteps=15000)

    box_w0 = [[57.66865614916953, -66.09241133078703, 47.43779192106421, -0.6862780950091272, 0.04550073987392385, -0.36216991360120393], [-12.10727872905934, -17.556470673741607, 7.7552881580976, -0.1300187288715955, -0.023618199542192752, 0.08686283408067244]]
    t,box_ws = integrator.run(box_w0, dt=1., nsteps=15000)

    # my classify
    orb_type = classify_orbit(loop_ws)
    for j in range(len(loop_w0)):
        assert np.all(orb_type[j] == sanders_classify(loop_ws[:,j]))

    orb_type = classify_orbit(box_ws)
    for j in range(len(box_w0)):
        assert np.all(orb_type[j] == sanders_classify(box_ws[:,j]))

def plot_orbit(w,ix=None):
    fig,axes = plt.subplots(1,3,figsize=(12,5),sharex=True,sharey=True)
    if ix is None:
        for ii in range(w.shape[1]):
            axes[0].plot(w[:,ii,0], w[:,ii,1], marker=None)
            axes[1].plot(w[:,ii,0], w[:,ii,2], marker=None)
            axes[2].plot(w[:,ii,1], w[:,ii,2], marker=None)
    else:
        axes[0].plot(w[:,ix,0], w[:,ix,1], marker=None)
        axes[1].plot(w[:,ix,0], w[:,ix,2], marker=None)
        axes[2].plot(w[:,ix,1], w[:,ix,2], marker=None)

    axes[0].set_xlabel("X")
    axes[0].set_ylabel("Y")

    axes[1].set_xlabel("X")
    axes[1].set_ylabel("Z")

    axes[2].set_xlabel("Y")
    axes[2].set_ylabel("Z")
    fig.tight_layout()
    return fig

def sanders_nvecs(N_max, dx, dy, dz):
    from itertools import product
    NNx = range(-N_max, N_max+1, dx)
    NNy = range(-N_max, N_max+1, dy)
    NNz = range(-N_max, N_max+1, dz)
    n_vectors = np.array([[i,j,k] for (i,j,k) in product(NNx,NNy,NNz)
                          if(not(i==0 and j==0 and k==0)            # exclude zero vector
                             and (k>0                               # northern hemisphere
                                  or (k==0 and j>0)                 # half of x-y plane
                                  or (k==0 and j==0 and i>0))       # half of x axis
                             and np.sqrt(i*i+j*j+k*k)<=N_max)])     # inside sphere
    return n_vectors

def test_nvecs():
    nvecs = generate_n_vectors(N_max=6, dx=2, dy=2, dz=2)
    nvecs_sanders = sanders_nvecs(N_max=6, dx=2, dy=2, dz=2)

    assert np.all(nvecs == nvecs_sanders)

def test_compare():
    import solver
    logger.setLevel(logging.ERROR)
    AA = np.random.uniform(0., 100., size=(1000,6))

    A1,b1 = solver.solver(AA, N_max=6, symNx=2)
    A2,b2 = action_solver(AA, N_max=6, dx=2, dy=2, dz=2)

    assert np.allclose(A1, A2)
    assert np.allclose(b1, b2)

class TestActions(object):

    def setup(self):
        self.usys = (u.kpc, u.Msun, u.Myr)
        self.potential = LM10Potential()
        acc = lambda t,x: self.potential.acceleration(x)
        self.integrator = LeapfrogIntegrator(acc)

    def test_box(self):
        return
        box_w0 = [-59.420, 53.435, -26.473, -0.1943, 0.0601, -0.1347]
        t,w = integrator.run(box_w0, dt=1., nsteps=15000)
        fig = plot_orbit(w,ix=0)
        fig.savefig(os.path.join(plot_path,"box.png"))
        actions,angles,nvecs = find_actions(t, w[:,0], N_max=6, usys=self.usys)

    def test_loop(self):
        N_max = 6

        loop_w0 = np.append(([14.69, 1.8, 0.12]*u.kpc).decompose(self.usys).value,
                            ([15.97, -128.9, 44.68]*u.km/u.s).decompose(self.usys).value)
        t,w = self.integrator.run(loop_w0, dt=0.5, nsteps=20000)

        w2 = w.copy()
        w2[:,0,3:] = (w2[:,0,3:]*u.kpc/u.Myr).to(u.km/u.s).value
        act,ang,n_vec,toy_aa,pars = genfunc_3d.find_actions(w2[:,0], t/1000., N_matrix=N_max)
        print(act[:3])
        print(ang[3:6])
        # return

        fig = plot_orbit(w,ix=0)
        fig.savefig(os.path.join(plot_path,"loop.png"))

        actions,angles,nvecs = find_actions(t, w[:,0], N_max=N_max, usys=self.usys)
        J = (actions[:3]*u.kpc**2/u.Myr).to(u.kpc*u.km/u.s)
        print(J)
        omega = (angles[3:6]/u.Myr).to(1/u.Gyr)
        print(omega)
        theta = (angles[:3,None] + angles[3:6,None]*t[np.newaxis]) % 2*np.pi

        return

        fig,axes = plt.subplots(1,2,sharex=True,sharey=True,figsize=(10,5))
        axes[0].plot(theta[0]/np.pi, theta[1]/np.pi, alpha=0.2, marker=None)
        axes[1].plot(theta[0]/np.pi, theta[2]/np.pi, alpha=0.2, marker=None)
        axes[0].set_xlim(0,2)
        axes[0].set_ylim(0,2)
        fig.savefig(os.path.join(plot_path,"loop_angles.png"))
<commit_msg>test loop orbit<commit_after># coding: utf-8

""" Test action-angle stuff """

from __future__ import division, print_function

__author__ = "adrn <adrn@astro.columbia.edu>"

# Standard library
import os, sys
import logging

# Third-party
import matplotlib.pyplot as plt
import numpy as np
from astropy import log as logger
import astropy.units as u

# Project
from ...integrate import LeapfrogIntegrator
from ...potential.lm10 import LM10Potential
from ..actionangle import *

logger.setLevel(logging.DEBUG)

plot_path = "plots/tests/dynamics/actionangle"
if not os.path.exists(plot_path):
    os.makedirs(plot_path)

# HACK:
sys.path.append("/Users/adrian/Downloads/genfunc-master")
import genfunc_3d

def angmom(x):
    return np.array([x[1]*x[5]-x[2]*x[4],x[2]*x[3]-x[0]*x[5],x[0]*x[4]-x[1]*x[3]])

def sanders_classify(X):
    L=angmom(X[0])
    loop = np.array([1,1,1])
    for i in X[1:]:
        L0 = angmom(i)
        if(L0[0]*L[0]<0.):
            loop[0] = 0
        if(L0[1]*L[1]<0.):
            loop[1] = 0
        if(L0[2]*L[2]<0.):
            loop[2] = 0
    return loop

def test_classify():
    usys = (u.kpc, u.Msun, u.Myr)
    potential = NFWPotential(v_h=(121.858*u.km/u.s).decompose(usys).value,
                             r_h=20., q1=0.86, q2=1., q3=1.18, usys=usys)
    acc = lambda t,x: potential.acceleration(x)
    integrator = LeapfrogIntegrator(acc)

    # initial conditions
    loop_w0 = [[6.975016793191392, -93.85342183505938, -71.90978460109265, -0.19151220547102255, -0.5944685489722188, 0.4262481187389783], [-119.85377948180077, -50.68671610744867, -10.05148560039928, -0.3351091185863992, -0.42681239582943836, -0.2512200315205476]]
    t,loop_ws = integrator.run(loop_w0, dt=1., nsteps=15000)

    box_w0 = [[57.66865614916953, -66.09241133078703, 47.43779192106421, -0.6862780950091272, 0.04550073987392385, -0.36216991360120393], [-12.10727872905934, -17.556470673741607, 7.7552881580976, -0.1300187288715955, -0.023618199542192752, 0.08686283408067244]]
    t,box_ws = integrator.run(box_w0, dt=1., nsteps=15000)

    # my classify
    orb_type = classify_orbit(loop_ws)
    for j in range(len(loop_w0)):
        assert np.all(orb_type[j] == sanders_classify(loop_ws[:,j]))

    orb_type = classify_orbit(box_ws)
    for j in range(len(box_w0)):
        assert np.all(orb_type[j] == sanders_classify(box_ws[:,j]))

def plot_orbit(w,ix=None):
    fig,axes = plt.subplots(1,3,figsize=(12,5),sharex=True,sharey=True)
    if ix is None:
        for ii in range(w.shape[1]):
            axes[0].plot(w[:,ii,0], w[:,ii,1], marker=None)
            axes[1].plot(w[:,ii,0], w[:,ii,2], marker=None)
            axes[2].plot(w[:,ii,1], w[:,ii,2], marker=None)
    else:
        axes[0].plot(w[:,ix,0], w[:,ix,1], marker=None)
        axes[1].plot(w[:,ix,0], w[:,ix,2], marker=None)
        axes[2].plot(w[:,ix,1], w[:,ix,2], marker=None)

    axes[0].set_xlabel("X")
    axes[0].set_ylabel("Y")

    axes[1].set_xlabel("X")
    axes[1].set_ylabel("Z")

    axes[2].set_xlabel("Y")
    axes[2].set_ylabel("Z")
    fig.tight_layout()
    return fig

def sanders_nvecs(N_max, dx, dy, dz):
    from itertools import product
    NNx = range(-N_max, N_max+1, dx)
    NNy = range(-N_max, N_max+1, dy)
    NNz = range(-N_max, N_max+1, dz)
    n_vectors = np.array([[i,j,k] for (i,j,k) in product(NNx,NNy,NNz)
                          if(not(i==0 and j==0 and k==0)            # exclude zero vector
                             and (k>0                               # northern hemisphere
                                  or (k==0 and j>0)                 # half of x-y plane
                                  or (k==0 and j==0 and i>0))       # half of x axis
                             and np.sqrt(i*i+j*j+k*k)<=N_max)])     # inside sphere
    return n_vectors

def test_nvecs():
    nvecs = generate_n_vectors(N_max=6, dx=2, dy=2, dz=2)
    nvecs_sanders = sanders_nvecs(N_max=6, dx=2, dy=2, dz=2)

    assert np.all(nvecs == nvecs_sanders)

def test_compare_action_prepare():
    from ..actionangle import _action_prepare
    import solver
    logger.setLevel(logging.ERROR)
    AA = np.random.uniform(0., 100., size=(1000,6))

    A1,b1 = solver.solver(AA, N_max=6, symNx=2)
    A2,b2,n = _action_prepare(AA, N_max=6, dx=2, dy=2, dz=2)

    assert np.allclose(A1, A2)
    assert np.allclose(b1, b2)

def test_compare_angle_prepare():
    from ..actionangle import _angle_prepare
    import solver
    logger.setLevel(logging.ERROR)
    AA = np.random.uniform(0., 100., size=(1000,6))
    t = np.linspace(0., 100., 1000)

    A1,b1 = solver.angle_solver(AA, t, N_max=6, sign=1., symNx=2)
    A2,b2,n = _angle_prepare(AA, t, N_max=6, dx=2, dy=2, dz=2)

    # row = slice(None,None)
    # col = slice(None,None)
    # assert np.allclose(A1[row,col], A2[row,col])

    assert np.allclose(A1, A2)
    assert np.allclose(b1, b2)

class TestActions(object):

    def setup(self):
        self.usys = (u.kpc, u.Msun, u.Myr)
        self.potential = LM10Potential()
        acc = lambda t,x: self.potential.acceleration(x)
        self.integrator = LeapfrogIntegrator(acc)

    def test_box(self):
        return
        box_w0 = [-59.420, 53.435, -26.473, -0.1943, 0.0601, -0.1347]
        t,w = integrator.run(box_w0, dt=1., nsteps=15000)
        fig = plot_orbit(w,ix=0)
        fig.savefig(os.path.join(plot_path,"box.png"))
        actions,angles,nvecs = find_actions(t, w[:,0], N_max=6, usys=self.usys)

    def test_loop(self):
        N_max = 6

        loop_w0 = np.append(([14.69, 1.8, 0.12]*u.kpc).decompose(self.usys).value,
                            ([15.97, -128.9, 44.68]*u.km/u.s).decompose(self.usys).value)
        t,w = self.integrator.run(loop_w0, dt=0.5, nsteps=20000)

        w2 = w.copy()
        w2[:,0,3:] = (w2[:,0,3:]*u.kpc/u.Myr).to(u.km/u.s).value
        act,ang,n_vec,toy_aa,pars = genfunc_3d.find_actions(w2[:,0], t/1000., N_matrix=N_max)
        print(act[:3])
        print(ang[3:6])
        # return

        fig = plot_orbit(w,ix=0)
        fig.savefig(os.path.join(plot_path,"loop.png"))

        actions,angles,nvecs = find_actions(t, w[:,0], N_max=N_max, usys=self.usys)
        J = (actions[:3]*u.kpc**2/u.Myr).to(u.kpc*u.km/u.s)
        print(J)
        omega = (angles[3:6]/u.Myr).to(1/u.Gyr)
        print(omega)
        theta = (angles[:3,None] + angles[3:6,None]*t[np.newaxis]) % 2*np.pi

        return

        fig,axes = plt.subplots(1,2,sharex=True,sharey=True,figsize=(10,5))
        axes[0].plot(theta[0]/np.pi, theta[1]/np.pi, alpha=0.2, marker=None)
        axes[1].plot(theta[0]/np.pi, theta[2]/np.pi, alpha=0.2, marker=None)
        axes[0].set_xlim(0,2)
        axes[0].set_ylim(0,2)
        fig.savefig(os.path.join(plot_path,"loop_angles.png"))
<|endoftext|>


<commit_before>import sublime, sublime_plugin
import math
import re

class cfunittestableCommand(sublime_plugin.TextCommand):
	def run(self, edit):

		#write general stats
		f = self.view
		returnMessage = "\nCFUnitTestable \n\nGeneral Stats:\n==========================================================================================================================\n"
		returnMessage += "File: "+str(f.file_name())+"\nSize: ~"+str(f.size()/1024)+"Kb ("+str(f.size())+" bytes)\n"
		all = self.view.find_all("[\s\S]*")
		self.view.add_regions("AllContent", all, "source", sublime.HIDDEN)
		g = self.view.get_regions("AllContent")
		for allregion in g:
			h = len(self.view.substr(allregion))

		#get all functions
		allMethods = self.view.find_all("<cffunction[\s\S]*?<\/cffunction>", sublime.IGNORECASE)
		allPublicMethods = []
		PrivateAndRemoteIndexes = []

		#loop through functions and find all private and remote functions
		for idx,method in enumerate(allMethods):
			methodLineByLine = self.view.split_by_newlines(method)
			re_accessRemoteOrPrivate = re.compile("access\s*\=\s*[\"\'](remote|private)[\"\']", re.IGNORECASE)
			for line in methodLineByLine:
				foundAccessRemoteOrPRivate = re_accessRemoteOrPrivate.search(self.view.substr(line))
				if foundAccessRemoteOrPRivate:
					PrivateAndRemoteIndexes.append(idx)

		#loop through functions and store all public remote methods
		for idx,method in enumerate(allMethods):
			if idx not in PrivateAndRemoteIndexes:
				allPublicMethods.append(method)

		returnMessage += "Methods:\n\t" + str(len(allPublicMethods)) + " Public\n\t" + str(len(PrivateAndRemoteIndexes)) + (" Private and/or Remote\n")
		returnMessage += "\nPublic Methods:"
		returnMessage += "\n==========================================================================================================================\n"

		#retreive all method names
		methodNames = []
		for method in allMethods:
			methodLineByLine = self.view.split_by_newlines(method)
			re_LookFor_MethodName = re.compile("name\s*\=\s*[\"\']", re.IGNORECASE)
			for line in methodLineByLine:
				if re_LookFor_MethodName.search(self.view.substr(line)):
					for splittedItem in self.view.substr(line).split():
						if re_LookFor_MethodName.search(splittedItem):
							partialName = re.sub("^[^\"]*?\"","",str(splittedItem))
							methodNames.append(re.sub("(\"|>)","",str(partialName)))
					break

		#check for dependencies
		for method in allPublicMethods:
			dependencies = []
			QueryDependencies = []
			methodName = ""
			methodLineByLine = self.view.split_by_newlines(method)
			re_LookFor_MethodName = re.compile("name\s*\=\s*[\"\']", re.IGNORECASE)
			re_LookFor_CreateObject = re.compile("CreateObject", re.IGNORECASE)
			re_LookFor_Functions = re.compile("(?<!response)(?<!result)\.[A-Za-z\d_]+\(", re.IGNORECASE)
			get_allQueryDependencies = self.view.find_all("<cfquery[\s\S]*?<\/cfquery>", sublime.IGNORECASE)

			for line in methodLineByLine:

				#get the method name
				if not len(methodName) and re_LookFor_MethodName.search(self.view.substr(line)):
					for splittedItem in self.view.substr(line).split():
						if re_LookFor_MethodName.search(splittedItem):
							methodName = re.sub(">","",str(splittedItem))
							break

				#look for object dependencies
				if re_LookFor_CreateObject.search(self.view.substr(line)):
					(row, col) = self.view.rowcol(line.begin())
					dependencies.append("Object dependency found on line " +str(row+1))

				#look for function dependencies
				if re_LookFor_Functions.search(self.view.substr(line)):
					(row, col) = self.view.rowcol(line.begin())
					dependencies.append("Function dependency found on line " +str(row+1)) # + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))

				#look for function dependencies
				for pubMethodName in methodNames:
					re_LookFor_MethodCall = re.compile("(?<![a-zA-Z_\d])" +pubMethodName +"\(")
					if re_LookFor_MethodCall.search(self.view.substr(line)):
						(row, col) = self.view.rowcol(line.begin())
						dependencies.append("Function dependency found on line " +str(row+1)) # + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))

				#look for query dependencies
				for idx,queryDependency in enumerate(get_allQueryDependencies):
					if queryDependency.intersects(line):
						(row, col) = self.view.rowcol(line.begin())
						dependencies.append("Query dependency found on line " +str(row+1))# + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))
						QueryDependencies.append("Query dependency found on line " +str(row+1))# + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))
						del get_allQueryDependencies[idx]
						break

			#output method name and dependencies
			functionHeader = ""
			if len(QueryDependencies):
				functionHeader = "\n[BAD] Method: " + methodName + "  -  This method can not be unit tested until the query dependencies are moved to DAOs\n"
			else:
				functionHeader += "\n[OK] Method: " + methodName + "  -  This method can be unit tested\n"
			returnMessage += functionHeader
			for i in range(1,len(functionHeader)):
				returnMessage +="-"
			returnMessage += "\n"
			if len(dependencies):
				returnMessage += "Dependencies found. Please mock the following:"
				for dependency in dependencies:
					returnMessage += "\n\t" + dependency
				returnMessage += "\n"
			returnMessage += "\n"

		#send to new file
		w = self.view.window()
		w.run_command("new_file")
		v = w.active_view()
		v.insert(edit,0,returnMessage)

		<commit_msg>Added support for all access types.<commit_after>import sublime, sublime_plugin
import math
import re

class cfunittestableCommand(sublime_plugin.TextCommand):
	def run(self, edit):

		#write general stats
		f = self.view
		returnMessage = "\nCFUnitTestable \n\nGeneral Stats:\n==========================================================================================================================\n"
		returnMessage += "File: "+str(f.file_name())+"\nSize: ~"+str(f.size()/1024)+"Kb ("+str(f.size())+" bytes)\n"
		all = self.view.find_all("[\s\S]*")
		self.view.add_regions("AllContent", all, "source", sublime.HIDDEN)
		g = self.view.get_regions("AllContent")
		for allregion in g:
			h = len(self.view.substr(allregion))

		#get all functions
		allMethods = self.view.find_all("<cffunction[\s\S]*?<\/cffunction>", sublime.IGNORECASE)

		PublicMethodIndexes = []
		PrivateMethodIndexes = []
		RemoteMethodIndexes = []
		PackageMethodIndexes = []

		#loop through functions and find all private and remote functions
		for idx,method in enumerate(allMethods):
			methodLineByLine = self.view.split_by_newlines(method)
			re_accessPublic = re.compile("access\s*\=\s*[\"\'](public)[\"\']", re.IGNORECASE)
			re_accessRemote = re.compile("access\s*\=\s*[\"\'](remote)[\"\']", re.IGNORECASE)
			re_accessPrivate = re.compile("access\s*\=\s*[\"\'](private)[\"\']", re.IGNORECASE)
			re_accessPackage = re.compile("access\s*\=\s*[\"\'](package)[\"\']", re.IGNORECASE)

			for line in methodLineByLine:
				foundAccessPublic = re_accessPublic.search(self.view.substr(line))
				if foundAccessPublic:
					PublicMethodIndexes.append(idx)

			for line in methodLineByLine:
				foundAccessRemote = re_accessRemote.search(self.view.substr(line))
				if foundAccessRemote:
					RemoteMethodIndexes.append(idx)

			for line in methodLineByLine:
				foundAccessPrivate = re_accessPrivate.search(self.view.substr(line))
				if foundAccessPrivate:
					PrivateMethodIndexes.append(idx)

			for line in methodLineByLine:
				foundAccessPackage = re_accessPackage.search(self.view.substr(line))
				if foundAccessPackage:
					PackageMethodIndexes.append(idx)

		returnMessage += "Methods:\n\t" + str(len(PublicMethodIndexes)) + " Public\n\t" + str(len(PrivateMethodIndexes)) + " Private\n\t" + str(len(RemoteMethodIndexes)) + " Remote\n\t" + str(len(PackageMethodIndexes)) + " Package"
		returnMessage += "\nPublic Methods:"
		returnMessage += "\n==========================================================================================================================\n"

		#retreive all method names
		methodNames = []
		for method in allMethods:
			methodLineByLine = self.view.split_by_newlines(method)
			re_LookFor_MethodName = re.compile("name\s*\=\s*[\"\']", re.IGNORECASE)
			for line in methodLineByLine:
				if re_LookFor_MethodName.search(self.view.substr(line)):
					for splittedItem in self.view.substr(line).split():
						if re_LookFor_MethodName.search(splittedItem):
							partialName = re.sub("^[^\"]*?\"","",str(splittedItem))
							methodNames.append(re.sub("(\"|>)","",str(partialName)))
					break

		#check for dependencies
		for idx,method in enumerate(allMethods):
			dependencies = []
			QueryDependencies = []
			methodName = ""
			methodLineByLine = self.view.split_by_newlines(method)
			re_LookFor_MethodName = re.compile("name\s*\=\s*[\"\']", re.IGNORECASE)
			re_LookFor_CreateObject = re.compile("CreateObject", re.IGNORECASE)
			re_LookFor_Functions = re.compile("(?<!response)(?<!result)\.[A-Za-z\d_]+\(", re.IGNORECASE)
			get_allQueryDependencies = self.view.find_all("<cfquery[\s\S]*?<\/cfquery>", sublime.IGNORECASE)

			for line in methodLineByLine:

				#get the method name
				if not len(methodName) and re_LookFor_MethodName.search(self.view.substr(line)):
					for splittedItem in self.view.substr(line).split():
						if re_LookFor_MethodName.search(splittedItem):
							methodName = re.sub(">","",str(splittedItem))
							break

				#get method access
				if not len(methodName) and re_LookFor_MethodName.search(self.view.substr(line)):
					for splittedItem in self.view.substr(line).split():
						if re_LookFor_MethodName.search(splittedItem):
							methodName = re.sub(">","",str(splittedItem))
							break

				#look for object dependencies
				if re_LookFor_CreateObject.search(self.view.substr(line)):
					(row, col) = self.view.rowcol(line.begin())
					dependencies.append("Object dependency found on line " +str(row+1))

				#look for function dependencies
				if re_LookFor_Functions.search(self.view.substr(line)):
					(row, col) = self.view.rowcol(line.begin())
					dependencies.append("Function dependency found on line " +str(row+1)) # + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))

				#look for function dependencies
				for pubMethodName in methodNames:
					re_LookFor_MethodCall = re.compile("(?<![a-zA-Z_\d])" +pubMethodName +"\(")
					if re_LookFor_MethodCall.search(self.view.substr(line)):
						(row, col) = self.view.rowcol(line.begin())
						dependencies.append("Function dependency found on line " +str(row+1)) # + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))

				#look for query dependencies
				for i,queryDependency in enumerate(get_allQueryDependencies):
					if queryDependency.intersects(line):
						(row, col) = self.view.rowcol(line.begin())
						dependencies.append("Query dependency found on line " +str(row+1))# + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))
						QueryDependencies.append("Query dependency found on line " +str(row+1))# + ": " + re.sub("^[\t ]*?","\t",self.view.substr(line)))
						del get_allQueryDependencies[i]
						break

			#output method name and dependencies
			functionHeader = ""
			if idx in PackageMethodIndexes:
				functionHeader = "\n[BAD] Method: " + methodName + " - This method can not be unit tested because it is confined to a package (access=\"package\")\n"
			elif len(QueryDependencies):
				functionHeader = "\n[BAD] Method: " + methodName + " - This method can not be unit tested until the query dependencies are moved to DAOs\Gateways\n"
			else:
				functionHeader += "\n[OK] Method: " + methodName + " - This method can be unit tested\n"
			returnMessage += functionHeader
			for k in range(1,len(functionHeader)):
				returnMessage +="-"
			returnMessage += "\n"
			if idx in PrivateMethodIndexes:
				returnMessage += "(!HINT - This is a private method. Use \"makePublic\" to test it.)\n"
			if len(dependencies):
				returnMessage += "Dependencies found. Please mock the following:"
				for dependency in dependencies:
					returnMessage += "\n\t" + dependency
				returnMessage += "\n"
			returnMessage += "\n"

		#send to new file
		w = self.view.window()
		w.run_command("new_file")
		v = w.active_view()
		v.insert(edit,0,returnMessage)

		<|endoftext|>


<commit_before>import requests
from bs4 import BeautifulSoup
import time

def is_number(s):
    """
    Check and parse entered value as a number
    """
    try:
        float(s)
        return True
    except ValueError:
        return False

def cg_accumulate(year, dep, degree_choice, sg_cg_choice, user_cg):

	# List of departments with Integrated M.Sc. (5 year courses)
	msc_dep_list = ["GG", "EX", "MA", "CY", "HS", "PH"]
	msc_dep = False
	dep_rank = 1

	print ""
	fname = "Output.txt"
	roll_count = 10000
	if degree_choice == "2":
		roll_count = 30000
	if dep in msc_dep_list:
		roll_count = 20000
		msc_dep = True

	student_count = 0
	flag = False
	cg_total = 0.00
	sg_total = 0.00
	bad_count = 0
	sg_list = []

	while True:
		roll_count += 1
		student_count += 1
		rollno = str(year) + str(dep) + str(roll_count)
		url_to_scrape = 'https://erp.iitkgp.ernet.in/StudentPerformance/view_performance.jsp?rollno=' + rollno
		name_flag = False
		flag = False

		try:
			r = requests.get(url_to_scrape)
		except Exception:
			print "ConnectionError on :" + str(roll_count)
			print "Retrying...."
			student_count -= 1
			roll_count -= 1
			continue
		soup = BeautifulSoup(r.text, "html.parser")

		with open(fname, "w") as text_file:
			text_file.write("{}".format(soup))

		with open(fname) as f:
			content = f.readlines()

		for line in content:
			if len(content) < 40:
				flag = True
				bad_count += 1
				student_count -= 1
				break

			bad_count = 0

			if line.find("Name") != -1 and not name_flag:
				idx = 24
				while(line[idx]!='<'):
					idx += 1
				name = line[24:idx]
				name_flag = True

			if sg_cg_choice == "1" or sg_cg_choice == "4":
				if line.find("CGPA") != -1:
					if line[4] != "<" and is_number(line[31:35]):
						if sg_cg_choice == "4":
							if user_cg < float(line[31:35]):
								dep_rank += 1
						else:
							print "Roll Num : " + str(rollno) + "	CG : " + str(line[31:35]) + "	Name : " + str(name)
							cg_total += float(line[31:35])
						break
			elif sg_cg_choice == "2":
				if line.find("SGPA") != -1 and is_number(line[25:29]):
					print "Roll Num : " + str(rollno) + "	SGPA in most recent semester : " + str(line[25:29]) + "	Name : " + str(name)
					sg_total += float(line[25:29])
					break
			elif sg_cg_choice == "3":
				if line.find("SGPA") != -1 and is_number(line[25:29]):
					sg_list.append(str(line[25:29]))

		if sg_cg_choice == "3" and not flag:
			print "Roll Num : " + str(rollno) + "	SGPA list : " + str(sg_list) + "	Name : " + str(name)
			del sg_list[:]

		if flag and bad_count >= 5 and (degree_choice != "3" or roll_count > 30000 or msc_dep):
			break

		# Will not be executed for MSc Integrated Courses
		if flag and bad_count >= 5 and not msc_dep:
			roll_count = 30000
			print "Making transition to dual degree students..."
			continue

	student_count -= 1
	print ""
	print "__________________________________"
	print "Number of Students : " + str(student_count)
	if sg_cg_choice == "1":
		print "Total CG : " + str(cg_total)
		print "Average CG : " + str(cg_total / student_count)
	elif sg_cg_choice == "2":
		print "Total SG : " + str(sg_total)
		print "Average SG : " + str(sg_total / student_count)
	elif sg_cg_choice == "4":
		print "Your Department Rank is : " + str(dep_rank)
		if dep_rank < student_count/2:
			print "Good going. You are in the top half of your department"
		else:
			print "A bit more hard work can see you in the top half of your department"
	print "__________________________________"

def find_cg(roll_num):
	url_to_scrape = 'https://erp.iitkgp.ernet.in/StudentPerformance/view_performance.jsp?rollno=' + str(roll_num)
	fname = "Output.txt"
	try:
		r = requests.get(url_to_scrape)

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

		with open(fname, "w") as text_file:
			text_file.write("{}".format(soup))

		with open(fname) as f:
			content = f.readlines()

		if len(content) < 40:
			print "Invalid Roll Number!"
			return -1
		else:
			for line in content:
				if line.find("CGPA") != -1:
					if line[4] != "<" and is_number(line[31:35]):
						return float(line[31:35])
	except Exception:
		print "ConnectionError on you roll number. Please check your connection and try again!"
		key = raw_input("The program will now exit. Press enter")
		exit(0)

print "*** Welcome to CG Accumulator ***"

departments = ["AE", "AG", "AR", "BT", "CE", "CH", "CS", "CY", "EC", "EE", "EX", "GG", "HS", "IE", "IM", "MA", "ME", "MF", "MI", "MT", "NA", "PH", "QD"]
years = ["12","13","14","15"]
user_cg = 0.00

while True:
	print ""
	year = raw_input("Enter year (Available Choices : 12, 13, 14, 15) :  ")
	if year not in years:
		print "Please enter a valid year choice"
		continue
	print ""
	dep = raw_input("Enter Department :  ")
	while dep not in departments:
		print "Please enter a valid department!"
		print "P.S. Department name should be capitalised. Eg. \"CS\" and not \"cs\""
		dep = raw_input("Enter Valid Department again : ")
	print ""
	sg_cg_choice = raw_input("Do you want CG list (enter '1') \n or Most recent SG list (enter '2') \n or Entire SG history (enter '3') \n or Know your D.R. (enter '4')? :  ")
	while sg_cg_choice not in ["1", "2", "3", "4"]:
		print "Please enter a valid choice!"
		sg_cg_choice = raw_input("Enter valid choice again : ")

	if sg_cg_choice == "4":
		roll_num = raw_input("Enter last 5 digits of your roll number :  ")
		while len(roll_num) != 5 or find_cg(year + dep + roll_num) == -1:
			print "Please enter valid last 5 digits"
			roll_num = raw_input("Enter valid last 5 digits of your roll number again:  ")
		user_cg = find_cg(year + dep + roll_num)
		degree_choice = "3"
	else:
		degree_choice = raw_input("Enter choice : '1' for 4 years only, '2' for 5 years only, '3' for both :  ")
		while degree_choice not in ["1", "2", "3"]:
			print "Please enter a valid choice!"
			degree_choice = raw_input("Enter valid choice again : ")
		print ""
	break

print ""
print "Please wait while results are being accumulated, this may take a few minutes...."
print "Meanwhile, minimize this screen and think about what you are doing with your life."
print ""
var = cg_accumulate(year, dep, degree_choice,sg_cg_choice, user_cg)
print ""
key = raw_input("Press Enter to exit")

<commit_msg>styling changes<commit_after>import requests
from bs4 import BeautifulSoup
import time

def is_number(s):
    """
    Check and parse entered value as a number
    """
    try:
        float(s)
        return True
    except ValueError:
        return False

def cg_accumulate(year, dep, degree_choice, sg_cg_choice, user_cg):

	# List of departments with Integrated M.Sc. (5 year courses)
	msc_dep_list = ["GG", "EX", "MA", "CY", "HS", "PH"]
	msc_dep = False
	dep_rank = 1

	print ""
	fname = "Output.txt"
	roll_count = 10000
	if degree_choice == "2":
		roll_count = 30000
	if dep in msc_dep_list:
		roll_count = 20000
		msc_dep = True

	student_count = 0
	flag = False
	cg_total = 0.00
	sg_total = 0.00
	bad_count = 0
	sg_list = []

	while True:
		roll_count += 1
		student_count += 1
		rollno = str(year) + str(dep) + str(roll_count)
		url_to_scrape = 'https://erp.iitkgp.ernet.in/StudentPerformance/view_performance.jsp?rollno=' + rollno
		name_flag = False
		flag = False

		try:
			r = requests.get(url_to_scrape)
		except Exception:
			print "ConnectionError on :" + str(roll_count)
			print "Retrying...."
			student_count -= 1
			roll_count -= 1
			continue
		soup = BeautifulSoup(r.text, "html.parser")

		with open(fname, "w") as text_file:
			text_file.write("{}".format(soup))

		with open(fname) as f:
			content = f.readlines()

		for line in content:
			if len(content) < 40:
				flag = True
				bad_count += 1
				student_count -= 1
				break

			bad_count = 0

			if line.find("Name") != -1 and not name_flag:
				idx = 24
				while(line[idx]!='<'):
					idx += 1
				name = line[24:idx]
				name_flag = True

			if sg_cg_choice == "1" or sg_cg_choice == "4":
				if line.find("CGPA") != -1:
					if line[4] != "<" and is_number(line[31:35]):
						if sg_cg_choice == "4":
							if user_cg < float(line[31:35]):
								dep_rank += 1
						else:
							print "Roll Num : " + str(rollno) + "	CG : " + str(line[31:35]) + "	Name : " + str(name)
							cg_total += float(line[31:35])
						break
			elif sg_cg_choice == "2":
				if line.find("SGPA") != -1 and is_number(line[25:29]):
					print "Roll Num : " + str(rollno) + "	SGPA in most recent semester : " + str(line[25:29]) + "	Name : " + str(name)
					sg_total += float(line[25:29])
					break
			elif sg_cg_choice == "3":
				if line.find("SGPA") != -1 and is_number(line[25:29]):
					sg_list.append(str(line[25:29]))

		if sg_cg_choice == "3" and not flag:
			print "Roll Num : " + str(rollno) + "	SGPA list : " + str(sg_list) + "	Name : " + str(name)
			del sg_list[:]

		if flag and bad_count >= 5 and (degree_choice != "3" or roll_count > 30000 or msc_dep):
			break

		# Will not be executed for MSc Integrated Courses
		if flag and bad_count >= 5 and not msc_dep:
			roll_count = 30000
			print "Making transition to dual degree students..."
			continue

	student_count -= 1
	print ""
	print "__________________________________"
	print "Number of Students : " + str(student_count)
	if sg_cg_choice == "1":
		print "Total CG : " + str(cg_total)
		print "Average CG : " + str(cg_total / student_count)
	elif sg_cg_choice == "2":
		print "Total SG : " + str(sg_total)
		print "Average SG : " + str(sg_total / student_count)
	elif sg_cg_choice == "4":
		print "Your Department Rank is : " + str(dep_rank)
		if dep_rank < student_count/2:
			print "Good going. You are in the top half of your department"
		else:
			print "A bit more hard work can see you in the top half of your department"
	print "__________________________________"

def find_cg(roll_num):
	url_to_scrape = 'https://erp.iitkgp.ernet.in/StudentPerformance/view_performance.jsp?rollno=' + str(roll_num)
	fname = "Output.txt"
	try:
		r = requests.get(url_to_scrape)

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

		with open(fname, "w") as text_file:
			text_file.write("{}".format(soup))

		with open(fname) as f:
			content = f.readlines()

		if len(content) < 40:
			print "Invalid Roll Number!"
			return -1
		else:
			for line in content:
				if line.find("CGPA") != -1:
					if line[4] != "<" and is_number(line[31:35]):
						return float(line[31:35])
	except Exception:
		print "ConnectionError on you roll number. Please check your connection and try again!"
		key = raw_input("The program will now exit. Press enter")
		exit(0)

print "*** Welcome to CG Accumulator ***"

departments = ["AE", "AG", "AR", "BT", "CE", "CH", "CS", "CY", "EC", "EE", "EX", "GG", "HS", "IE", "IM", "MA", "ME", "MF", "MI", "MT", "NA", "PH", "QD"]
years = ["12","13","14","15"]
user_cg = 0.00

while True:
	print ""
	year = raw_input("Enter year (Available Choices : 12, 13, 14, 15) :  ")
	if year not in years:
		print "Please enter a valid year choice"
		continue
	print ""
	dep = raw_input("Enter Department :  ")
	while dep not in departments:
		print "Please enter a valid department!"
		print "P.S. Department name should be capitalised. Eg. \"CS\" and not \"cs\""
		dep = raw_input("Enter Valid Department again : ")
	print ""
	sg_cg_choice = raw_input("Do you want CG list (enter '1') \n or Most recent SG list (enter '2') \n or Entire SG history (enter '3') \n or Know your D.R. (enter '4')? :  ")
	while sg_cg_choice not in ["1", "2", "3", "4"]:
		print "Please enter a valid choice!"
		sg_cg_choice = raw_input("Enter valid choice again : ")

	if sg_cg_choice == "4":
		roll_num = raw_input("Enter last 5 digits of your roll number :  ")
		while len(roll_num) != 5 or find_cg(year + dep + roll_num) == -1:
			print "Please enter valid last 5 digits"
			roll_num = raw_input("Enter valid last 5 digits of your roll number again:  ")
		user_cg = find_cg(year + dep + roll_num)
		degree_choice = "3"
	else:
		print ""
		degree_choice = raw_input("Enter choice : '1' for 4 years only, '2' for 5 years only, '3' for both :  ")
		while degree_choice not in ["1", "2", "3"]:
			print "Please enter a valid choice!"
			degree_choice = raw_input("Enter valid choice again : ")
		print ""
	break

print ""
print "Please wait while results are being accumulated, this may take a few minutes...."
print "Meanwhile, minimize this screen and think about what you are doing with your life."
print ""
var = cg_accumulate(year, dep, degree_choice,sg_cg_choice, user_cg)
print ""
key = raw_input("Press Enter to exit")

<|endoftext|>


<commit_before>"""Summary
"""
import math
from PyQt5.QtCore import QPointF, QLineF, QRectF
from PyQt5.QtWidgets import QGraphicsObject
from PyQt5.QtWidgets import QGraphicsLineItem
from PyQt5.QtWidgets import QGraphicsEllipseItem
from cadnano.gui.views.sliceview import slicestyles as styles
from cadnano.gui.palette import getPenObj, getBrushObj, getNoPen

_RADIUS = styles.SLICE_HELIX_RADIUS
_DEFAULT_RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS)
HIGHLIGHT_WIDTH = styles.SLICE_HELIX_MOD_HILIGHT_WIDTH
_MOD_PEN = getPenObj(styles.BLUE_STROKE, HIGHLIGHT_WIDTH)
DELTA = (HIGHLIGHT_WIDTH - styles.SLICE_HELIX_STROKE_WIDTH)/2.
# _HOVER_RECT = _DEFAULT_RECT.adjusted(-DELTA, -DELTA, DELTA, DELTA)

_INACTIVE_PEN = getPenObj(styles.GRAY_STROKE, HIGHLIGHT_WIDTH)

class AbstractSliceTool(QGraphicsObject):
    """Summary

    Attributes:
        angles (TYPE): Description
        FILTER_NAME (str): Description
        is_started (bool): Description
        manager (TYPE): Description
        part_item (TYPE): Description
        sgv (TYPE): Description
        vectors (TYPE): Description
    """
    _RADIUS = styles.SLICE_HELIX_RADIUS
    _CENTER_OF_HELIX = QPointF(_RADIUS, _RADIUS)
    FILTER_NAME = 'virtual_helix'
    # _CENTER_OF_HELIX = QPointF(0. 0.)
    """Abstract base class to be subclassed by all other pathview tools."""
    def __init__(self, manager):
        """Summary

        Args:
            manager (TYPE): Description
        """
        super(AbstractSliceTool, self).__init__(parent=manager.viewroot)
        """ Pareting to viewroot to prevent orphan _line_item from occuring
        """
        self.sgv = None
        self.manager = manager
        self._active = False
        self._last_location = None
        self._line_item = QGraphicsLineItem(self)
        self._line_item.hide()
        self._vhi = None

        self.hide()
        self.is_started = False
        self.angles = [math.radians(x) for x in range(0, 360, 30)]
        self.vectors = self.setVectors()
        self.part_item = None

        self.vhi_hint_item = QGraphicsEllipseItem(_DEFAULT_RECT, self)
        self.vhi_hint_item.setPen(_MOD_PEN)
        self.vhi_hint_item.setZValue(styles.ZPARTITEM)
    # end def

    ######################## Drawing #######################################
    def setVectors(self):
        """Summary

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        return [QLineF(rad, rad,
                       rad*(1. + 2.*math.cos(x)), rad*(1. + 2.*math.sin(x))
                       ) for x in self.angles]
    # end def

    def setVirtualHelixItem(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.sliceview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        self._vhi = virtual_helix_item
        li = self._line_item
        li.setParentItem(virtual_helix_item)
        li.setLine(rad, rad, rad, rad)
        # li.setLine(0., 0., 0., 0.)
    # end def

    def setSelectionFilter(self, filter_name_list):
        if 'virtual_helix' in filter_name_list:
            self.vhi_hint_item.setPen(_MOD_PEN)
        else:
            self.vhi_hint_item.setPen(_INACTIVE_PEN)
    # end def

    def resetTool(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._line_item.setParentItem(self)

    def idNum(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._vhi is not None:
            return self._vhi.idNum()

    def setPartItem(self, part_item):
        """Summary

        Args:
            part_item (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.setParentItem(part_item)
        self.part_item = part_item
    # end def

    def boundingRect(self):
        """Required to prevent NotImplementedError()
        """
        return QRectF()

    def eventToPosition(self, part_item, event):
        """take an event and return a position as a QPointF
        update widget as well

        Args:
            part_item (TYPE): Description
            event (TYPE): Description
        """
        if self.is_started:
            pos = self.findNearestPoint(part_item, event.scenePos())
        else:
            pos =  event.pos()
        self.vhi_hint_item.setPos(  pos -
                                    QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        return pos
    # end def

    def setHintPos(self, pos):
        self.vhi_hint_item.setPos(  pos -
                                    QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
    # end def

    def findNearestPoint(self, part_item, target_scenepos):
        """
        Args:
            part_item (TYPE): Description
            target_scenepos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromScene(target_scenepos)

        line = li.line()
        mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos)

        # Check if the click happened on the origin VH
        if mouse_point_vec.length() < self._RADIUS:
            return part_item.mapFromScene(target_scenepos)

        angle_min = 9999
        direction_min = None
        for vector in self.vectors:
            angle_new = mouse_point_vec.angleTo(vector)
            if angle_new < angle_min:
                direction_min = vector
                angle_min = angle_new
        if direction_min is not None:
            li.setLine(direction_min)
            return part_item.mapFromItem(li, direction_min.p2())
        else:
            print("default point")
            line.setP2(pos)
            li.setLine(line)
            return part_item.mapFromItem(li, pos)
    # end def

    def findNextPoint(self, part_item, target_part_pos):
        """
        Args:
            part_item (TYPE): Description
            target_part_pos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromItem(part_item, target_part_pos)
        for i, vector in enumerate(self.vectors):
            if vector.p2() == pos:
                return part_item.mapFromItem(li, self.vectors[i - 1].p2())
        # origin VirtualHelixItem is overlapping destination VirtualHelixItem
        return part_item.mapFromItem(li, self.vectors[0].p2())
    # end def

    def hideLineItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.hide()
        li = self._line_item
        li.hide()
        li.setParentItem(self)
        line = li.line()
        line.setP2(self._CENTER_OF_HELIX)
        li.setLine(line)
        # li.hide()
        self.is_started = False
    # end def

    # def hoverEnterEvent(self, event):
    #     self.vhi_hint_item.show()
    #     #print("Slice VHI hoverEnterEvent")

    # # def hoverMoveEvent(self, event):
    #     # print("Slice VHI hoverMoveEvent")

    # def hoverLeaveEvent(self, event):
    #     # self.vhi_hint_item.hide()
    #     #print("Slice VHI hoverLeaveEvent")

    def hoverMoveEvent(self, part_item, event):
        """Summary

        Args:
            part_item (TYPE): Description
            event (TYPE): Description

        Returns:
            TYPE: Description
        """
        # self.vhi_hint_item.setPos(  event.pos()-
        #                             QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        pos = self.eventToPosition(part_item, event)
        return pos
    # end def

    def setActive(self, will_be_active, old_tool=None):
        """
        Called by SliceToolManager.setActiveTool when the tool becomes
        active. Used, for example, to show/hide tool-specific ui elements.

        Args:
            will_be_active (TYPE): Description
            old_tool (None, optional): Description
        """
        if self._active and not will_be_active:
            self.deactivate()
        self._active = will_be_active
        self.sgv = self.manager.window.slice_graphics_view
        if hasattr(self, 'getCustomContextMenu'):
            # print("connecting ccm")
            try:    # Hack to prevent multiple connections
                self.sgv.customContextMenuRequested.disconnect()
            except:
                pass
            self.sgv.customContextMenuRequested.connect(self.getCustomContextMenu)
    # end def

    def deactivate(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if hasattr(self, 'getCustomContextMenu'):
            # print("disconnecting ccm")
            self.sgv.customContextMenuRequested.disconnect(self.getCustomContextMenu)
        self.sgv = None
        self.is_started = False
        self.hideLineItem()
        self._vhi = None
        self.part_item = None
        self.hide()
        self._active = False
    # end def

    def isActive(self):
        """Returns isActive
        """
        return self._active
    # end def
# end class
<commit_msg>2.5.1:  Update value of svg in abstractslicetool<commit_after>"""Summary
"""
import math

from cadnano.gui.palette import getBrushObj, getNoPen, getPenObj
from cadnano.gui.views.sliceview import slicestyles as styles
from PyQt5.QtCore import QLineF, QPointF, QRectF
from PyQt5.QtWidgets import (QGraphicsEllipseItem, QGraphicsLineItem,
                             QGraphicsObject)

_RADIUS = styles.SLICE_HELIX_RADIUS
_DEFAULT_RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS)
HIGHLIGHT_WIDTH = styles.SLICE_HELIX_MOD_HILIGHT_WIDTH
_MOD_PEN = getPenObj(styles.BLUE_STROKE, HIGHLIGHT_WIDTH)
DELTA = (HIGHLIGHT_WIDTH - styles.SLICE_HELIX_STROKE_WIDTH)/2.
# _HOVER_RECT = _DEFAULT_RECT.adjusted(-DELTA, -DELTA, DELTA, DELTA)

_INACTIVE_PEN = getPenObj(styles.GRAY_STROKE, HIGHLIGHT_WIDTH)

class AbstractSliceTool(QGraphicsObject):
    """Summary

    Attributes:
        angles (TYPE): Description
        FILTER_NAME (str): Description
        is_started (bool): Description
        manager (TYPE): Description
        part_item (TYPE): Description
        sgv (TYPE): Description
        vectors (TYPE): Description
    """
    _RADIUS = styles.SLICE_HELIX_RADIUS
    _CENTER_OF_HELIX = QPointF(_RADIUS, _RADIUS)
    FILTER_NAME = 'virtual_helix'
    # _CENTER_OF_HELIX = QPointF(0. 0.)
    """Abstract base class to be subclassed by all other pathview tools."""
    def __init__(self, manager):
        """Summary

        Args:
            manager (TYPE): Description
        """
        super(AbstractSliceTool, self).__init__(parent=manager.viewroot)
        """ Pareting to viewroot to prevent orphan _line_item from occuring
        """
        self.sgv = None # SGV is "Slice Graphics View"
        self.manager = manager
        self._active = False
        self._last_location = None
        self._line_item = QGraphicsLineItem(self)
        self._line_item.hide()
        self._vhi = None

        self.hide()
        self.is_started = False
        self.angles = [math.radians(x) for x in range(0, 360, 30)]
        self.vectors = self.setVectors()
        self.part_item = None

        self.vhi_hint_item = QGraphicsEllipseItem(_DEFAULT_RECT, self)
        self.vhi_hint_item.setPen(_MOD_PEN)
        self.vhi_hint_item.setZValue(styles.ZPARTITEM)
    # end def

    ######################## Drawing #######################################
    def setVectors(self):
        """Summary

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        return [QLineF(rad, rad,
                       rad*(1. + 2.*math.cos(x)), rad*(1. + 2.*math.sin(x))
                       ) for x in self.angles]
    # end def

    def setVirtualHelixItem(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.sliceview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        rad = self._RADIUS
        self._vhi = virtual_helix_item
        li = self._line_item
        li.setParentItem(virtual_helix_item)
        li.setLine(rad, rad, rad, rad)
        # li.setLine(0., 0., 0., 0.)
    # end def

    def setSelectionFilter(self, filter_name_list):
        if 'virtual_helix' in filter_name_list:
            self.vhi_hint_item.setPen(_MOD_PEN)
        else:
            self.vhi_hint_item.setPen(_INACTIVE_PEN)
    # end def

    def resetTool(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._line_item.setParentItem(self)

    def idNum(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._vhi is not None:
            return self._vhi.idNum()

    def setPartItem(self, part_item):
        """Summary

        Args:
            part_item (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.setParentItem(part_item)
        self.part_item = part_item
    # end def

    def boundingRect(self):
        """Required to prevent NotImplementedError()
        """
        return QRectF()

    def eventToPosition(self, part_item, event):
        """take an event and return a position as a QPointF
        update widget as well

        Args:
            part_item (TYPE): Description
            event (TYPE): Description
        """
        if self.is_started:
            pos = self.findNearestPoint(part_item, event.scenePos())
        else:
            pos =  event.pos()
        self.vhi_hint_item.setPos(  pos -
                                    QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        return pos
    # end def

    def setHintPos(self, pos):
        self.vhi_hint_item.setPos(  pos -
                                    QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
    # end def

    def findNearestPoint(self, part_item, target_scenepos):
        """
        Args:
            part_item (TYPE): Description
            target_scenepos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromScene(target_scenepos)

        line = li.line()
        mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos)

        # Check if the click happened on the origin VH
        if mouse_point_vec.length() < self._RADIUS:
            return part_item.mapFromScene(target_scenepos)

        angle_min = 9999
        direction_min = None
        for vector in self.vectors:
            angle_new = mouse_point_vec.angleTo(vector)
            if angle_new < angle_min:
                direction_min = vector
                angle_min = angle_new
        if direction_min is not None:
            li.setLine(direction_min)
            return part_item.mapFromItem(li, direction_min.p2())
        else:
            print("default point")
            line.setP2(pos)
            li.setLine(line)
            return part_item.mapFromItem(li, pos)
    # end def

    def findNextPoint(self, part_item, target_part_pos):
        """
        Args:
            part_item (TYPE): Description
            target_part_pos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromItem(part_item, target_part_pos)
        for i, vector in enumerate(self.vectors):
            if vector.p2() == pos:
                return part_item.mapFromItem(li, self.vectors[i - 1].p2())
        # origin VirtualHelixItem is overlapping destination VirtualHelixItem
        return part_item.mapFromItem(li, self.vectors[0].p2())
    # end def

    def hideLineItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self.vhi_hint_item.hide()
        li = self._line_item
        li.hide()
        li.setParentItem(self)
        line = li.line()
        line.setP2(self._CENTER_OF_HELIX)
        li.setLine(line)
        # li.hide()
        self.is_started = False
    # end def

    # def hoverEnterEvent(self, event):
    #     self.vhi_hint_item.show()
    #     #print("Slice VHI hoverEnterEvent")

    # # def hoverMoveEvent(self, event):
    #     # print("Slice VHI hoverMoveEvent")

    # def hoverLeaveEvent(self, event):
    #     # self.vhi_hint_item.hide()
    #     #print("Slice VHI hoverLeaveEvent")

    def hoverMoveEvent(self, part_item, event):
        """Summary

        Args:
            part_item (TYPE): Description
            event (TYPE): Description

        Returns:
            TYPE: Description
        """
        # self.vhi_hint_item.setPos(  event.pos()-
        #                             QPointF(_RADIUS - DELTA, _RADIUS - DELTA))
        pos = self.eventToPosition(part_item, event)
        return pos
    # end def

    def setActive(self, will_be_active, old_tool=None):
        """
        Called by SliceToolManager.setActiveTool when the tool becomes
        active. Used, for example, to show/hide tool-specific ui elements.

        Args:
            will_be_active (TYPE): Description
            old_tool (None, optional): Description
        """
        if self._active and not will_be_active:
            self.deactivate()
        self._active = will_be_active
        self.sgv = self.manager.window.advanced_slice_graphics_view
        if hasattr(self, 'getCustomContextMenu'):
            # print("connecting ccm")
            try:    # Hack to prevent multiple connections
                self.sgv.customContextMenuRequested.disconnect()
            except:
                pass
            self.sgv.customContextMenuRequested.connect(self.getCustomContextMenu)
    # end def

    def deactivate(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if hasattr(self, 'getCustomContextMenu'):
            # print("disconnecting ccm")
            self.sgv.customContextMenuRequested.disconnect(self.getCustomContextMenu)
        self.sgv = None
        self.is_started = False
        self.hideLineItem()
        self._vhi = None
        self.part_item = None
        self.hide()
        self._active = False
    # end def

    def isActive(self):
        """Returns isActive
        """
        return self._active
    # end def
# end class
<|endoftext|>


<commit_before>from django.test import TestCase

from callisto_core.delivery.models import Report

from callisto_core.tests.test_base import ReportFlowHelper

class ReportEncryptionTest(
    ReportFlowHelper,
):

    def test_not_authorized_without_owner(self):
        self.report = Report.objects.create()
        response = self.client_post_report_pdf_view(skip_assertions=True)
        self.assertEqual(response.status_code, 403)

    def test_can_decrypt_without_setup(self):
        self.report = Report.objects.create(
            owner=self.user,
        )
        self.client_post_report_pdf_view()
<commit_msg>$ make clean<commit_after>from django.test import TestCase

from callisto_core.delivery.models import Report
from callisto_core.tests.test_base import ReportFlowHelper

class ReportEncryptionTest(
    ReportFlowHelper,
):

    def test_not_authorized_without_owner(self):
        self.report = Report.objects.create()
        response = self.client_post_report_pdf_view(skip_assertions=True)
        self.assertEqual(response.status_code, 403)

    def test_can_decrypt_without_setup(self):
        self.report = Report.objects.create(
            owner=self.user,
        )
        self.client_post_report_pdf_view()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# coding=utf-8
import sys
import signal
import os
from conf import base_url
from .instance_manager import InstanceManager
from flask import url_for, make_response
from flask.ext.restful.representations import json
from .interfaces.v0_routing import v0_routing
from .interfaces.v1_routing import v1_routing
from .interfaces.documentation import v0_documentation, v1_documentation
import os
from werkzeug.serving import run_simple
from flask import request
import dict2xml
from .app import app, api

#@api.representation("application/xml")
# def output_xml(data, code, headers=None):
#    """Makes a Flask response with a XML encoded body"""
#    data_xml = dict2xml.dict2xml({'response' :data})
#    resp = make_response(data_xml, code)
#    resp.headers.extend(headers or {})
#    return resp

@api.representation("text/jsonp")
@api.representation("application/jsonp")
def output_jsonp(data, code, headers=None):
    resp = json.output_json(data, code, headers)
    callback = request.args.get('callback', False)
    if callback:
        resp.data = str(callback) + '(' + resp.data + ')'
    return resp

v1_routing(api)
v0_routing(api)
v0_documentation(api)
v1_documentation(api)

def kill_thread(signal, frame):
    InstanceManager().stop()
    sys.exit(0)
config_file = 'Jormungandr.ini' if 'JORMUNGANDR_CONFIG_FILE' not in os.environ\
    else os.environ['JORMUNGANDR_CONFIG_FILE']
if __name__ == '__main__':
    signal.signal(signal.SIGINT, kill_thread)
    signal.signal(signal.SIGTERM, kill_thread)
    InstanceManager().initialisation()
    run_simple('localhost', 5000, app,
               use_evalex=True)

else:
    InstanceManager().initialisation()
<commit_msg>Jormungandr: fixed several bugs in api.py<commit_after>#!/usr/bin/env python
# coding=utf-8
import sys
import signal
import os
from jormungandr.instance_manager import InstanceManager
from flask import url_for, make_response
from flask.ext.restful.representations import json
from jormungandr.interfaces.v0_routing import v0_routing
from jormungandr.interfaces.v1_routing import v1_routing
from jormungandr.interfaces.documentation import v0_documentation, v1_documentation
import os
from werkzeug.serving import run_simple
from flask import request
import dict2xml
from jormungandr.app import app, api

#@api.representation("application/xml")
# def output_xml(data, code, headers=None):
#    """Makes a Flask response with a XML encoded body"""
#    data_xml = dict2xml.dict2xml({'response' :data})
#    resp = make_response(data_xml, code)
#    resp.headers.extend(headers or {})
#    return resp

@api.representation("text/jsonp")
@api.representation("application/jsonp")
def output_jsonp(data, code, headers=None):
    resp = json.output_json(data, code, headers)
    callback = request.args.get('callback', False)
    if callback:
        resp.data = str(callback) + '(' + resp.data + ')'
    return resp

v1_routing(api)
v0_routing(api)
v0_documentation(api)
v1_documentation(api)

def kill_thread(signal, frame):
    InstanceManager().stop()
    sys.exit(0)
config_file = 'Jormungandr.ini' if 'JORMUNGANDR_CONFIG_FILE' not in os.environ\
    else os.environ['JORMUNGANDR_CONFIG_FILE']
if __name__ == '__main__':
    signal.signal(signal.SIGINT, kill_thread)
    signal.signal(signal.SIGTERM, kill_thread)
    InstanceManager().initialisation()
    run_simple('localhost', 5000, app,
               use_evalex=True)

else:
    InstanceManager().initialisation()
<|endoftext|>


<commit_before>from django.conf.urls import patterns, url, include

from django.contrib import admin
admin.autodiscover()

from django.conf import settings

urlpatterns = patterns('',
	url (r'^admin/', include(admin.site.urls)),
	url (r'^$', 'levels.views.index', name='index'),
	url (r'^done/$', 'levels.views.done', name='done'),

	url (r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),

	url (r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'core/login.html'}, name="login"),
	url (r'^logout/$', 'django.contrib.auth.views.logout_then_login', name="logout_then_login"),
	url (r'^register/$', 'core.views.register', name="register"),
	url (r'^score/$', 'stats.views.score', name='score'),
	url (r'^attempts/$', 'stats.views.attempts', name='attempts'),
	url (r'^attempts/(?P<getnum>\d*)/$', 'stats.views.attempts'),
)
<commit_msg>Fixing indenting and line length<commit_after>from django.conf.urls import patterns, url, include

from django.contrib import admin
admin.autodiscover()

from django.conf import settings

urlpatterns = patterns('',
    url (r'^admin/', include(admin.site.urls)),
    url (r'^$', 'levels.views.index', name='index'),
    url (r'^done/$', 'levels.views.done', name='done'),

    url (r'^media/(?P<path>.*)$', 'django.views.static.serve',
        {'document_root': settings.MEDIA_ROOT}),

    url (r'^login/$', 'django.contrib.auth.views.login',
        {'template_name': 'core/login.html'}, name="login"),
    url (r'^logout/$', 'django.contrib.auth.views.logout_then_login',
        name="logout_then_login"),
    url (r'^register/$', 'core.views.register', name="register"),
    url (r'^score/$', 'stats.views.score', name='score'),
    url (r'^attempts/$', 'stats.views.attempts', name='attempts'),
    url (r'^attempts/(?P<getnum>\d*)/$', 'stats.views.attempts'),
)
<|endoftext|>


<commit_before># coding: utf-8
"""ExposureTask: a class representing an ongoing exposure with the detector"""
import datetime
import enum
import logging
import os
import pickle
import time
from typing import Optional

import h5py
import numpy as np
from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal as Signal

from ....dataclasses.exposure import Exposure
from ....dataclasses.header import Header
from ....dataclasses.sample import Sample
from ....devices.detector.pilatus.frontend import PilatusDetector
from ....devices.device.frontend import DeviceFrontend

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

class ExposureState(enum.Enum):
    Initializing = enum.auto()  # the detector is being initialized by the Exposer
    Pending = enum.auto()  # another image is being collected, wait for our turn
    Running = enum.auto()  # this image is being collected
    WaitingForImage = enum.auto()  # collection done, trying to load the image file from disk
    Finished = enum.auto()  # finished successfully, image have been loaded
    TimedOut = enum.auto()  # finished unsuccessfully, image file could not be found
    Stopped = enum.auto()  # finished, stopped on external request

class ExposureTask(QtCore.QObject):
    """Representation of a scheduled/running exposure

    The life of an exposure is the following, reflected by the `status` variable:
        - the exposure task is created in the "Initializing" state. This precedes the issuing of the start exposure
          command to the detector.
        - After the detector has acknowledged the exposure command, the exposure task goes into the "Running" state. If
          multiple exposures are requested, the first one will be "Running", the subsequent ones are "Pending".
        - "Pending" tasks become "Running" when all previous exposures have been done and the waiting times inbetween
          them are also elapsed. In this sense, the i-th exposure (i=1..) spends `exptime`*(i-1) + `expdelay`*(i-1) in
          the "Pending" state and finishes after i*`exptime` + (i-1)*`expdelay`.
        - When the exposure time has elapsed (on the clock of the computer, i.e. no interaction is needed with the
          detector hardware), the state turns to "WaitingForImage". In this state the program tries periodically to load
          the image file from the disk.
        - If the image file is found in the preferred timeout interval, the status gets to "Finished". This is success.
        - If the image file is not found even after the timeout has been elapsed, the status will be "TimedOut".

    The following signals are defined:

        - `exposurestarted`: emitted at the actual start of the exposure (estimated using the clock)
        - `exposureended`: emitted at the actual end of the exposure
        - `finished`: emitted when the image has been loaded / the image loading timeout has been spent

    :ivar prefix: file name prefix, e.g. 'crd', 'tst', 'scn', 'tra' etc.
    :type prefix: str
    :ivar fsn: file sequence number of this exposure
    :type fsn: int
    :ivar command_issue_time: the timestamp (a la time.monotonic()) when the detector was started
    :type command_issue_time: float
    :ivar command_ack_time: the timestamp (a la time.monotonic()) when the detector acknowledged the start command
    :type command_ack_time: float
    :ivar exptime: time of a single exposure (sec)
    :type exptime: float
    :ivar expdelay: delay between two subsequent exposures in a multi-exposure series (sec)
    :type expdelay: float
    :ivar imagetimeout: time before giving up on reading a finished image (sec)
    :type imagetimeout: float
    :ivar index: the 0-based index of this image in a multi-frame exposure
    :type index: int
    :ivar maskoverride: use a different mask
    :type maskoverride: str or None
    """
    # all times are from time.monotonic()
    prefix: str
    fsn: int
    firstfsn: int
    command_ack_time: Optional[float] = None  # when the detector backend process replied to the expose command
    exptime: float  # exposure time
    expdelay: float  # delay between exposures
    imagetimeout: float = 2.0  # timeout for waiting for the image.
    index: int  # 0-based index of this image in a multiple exposure sequence
    maskoverride: Optional[str] = None
    status: ExposureState = ExposureState.Initializing
    finished = Signal(bool, object)
    exposurestarted = Signal()
    exposureended = Signal()
    pendingtimer: Optional[int] = None
    runningtimer: Optional[int] = None
    waitforimagetimer: Optional[int] = None
    imageloadtimer: Optional[int] = None
    imageloadperiod: float = 0.1
    instrument: "Instrument"
    detector: PilatusDetector
    h5: Optional[h5py.File] = None

    def __init__(self, instrument: "Instrument", detector: PilatusDetector, prefix: str, fsn: int, index: int,
                 exptime: float, expdelay: float, maskoverride: Optional[str] = None, writenexus: bool = False):
        super().__init__()
        self.prefix = prefix
        self.fsn = fsn
        self.index = index
        self.exptime = exptime
        self.expdelay = expdelay
        self.exptime = exptime
        self.maskoverride = maskoverride
        self.status = ExposureState.Initializing
        self.instrument = instrument
        self.detector = detector
        self.writenexus = writenexus
        if writenexus:
            targetdir = os.path.join(self.instrument.io.getSubDir('nexus'), prefix)
            os.makedirs(targetdir, exist_ok=True)
            self.h5 = h5py.File(
                os.path.join(targetdir, self.instrument.io.formatFileName(prefix, fsn, '.nxs')), 'w',
                libver='latest')
            grp = self.h5.require_group(f'{prefix}_{fsn:05d}')
            grp.attrs['NX_class'] = 'NXentry'
            self.instrument.toNeXus(grp)

    @property
    def starttime(self):
        """expected start time of this image"""
        return self.command_ack_time + self.index * (self.exptime + self.expdelay)

    @property
    def endtime(self):
        """expected end time of this image"""
        return self.starttime + self.exptime

    def timerEvent(self, event: QtCore.QTimerEvent) -> None:
        if (event.timerId() == self.pendingtimer) and (self.status == ExposureState.Pending):
            # the exposure is supposedly started
            self.onExposureStarted()
            self.killTimer(self.pendingtimer)
            self.pendingtimer = None
        elif (event.timerId() == self.runningtimer) and (self.status == ExposureState.Running):
            # the exposure is supposedly ended
            self.onExposureFinished()
            self.killTimer(self.runningtimer)
            self.runningtimer = None
        elif (event.timerId() == self.waitforimagetimer) and (self.status == ExposureState.WaitingForImage):
            # image waiting timeout spent
            self.killTimer(self.waitforimagetimer)
            self.waitforimagetimer = None
            self.status = ExposureState.TimedOut
            self.finished.emit(False, None)
        elif (event.timerId() == self.imageloadtimer) and (self.status == ExposureState.WaitingForImage):
            # try to load the image
            try:
                image = self.instrument.io.loadCBF(self.prefix, self.fsn, check_local=False)
            except FileNotFoundError:
                # the file is not there (yet?). Wait until timeout
                pass
            else:
                # the file has been found. Kill the timers
                self.killTimer(self.waitforimagetimer)
                self.killTimer(self.imageloadtimer)
                self.waitforimagetimer = None
                self.imageloadtimer = None
                self.status = ExposureState.Finished
                # construct the metadata
                header = self.createHeader()
                self.instrument.io.imageReceived(self.prefix, self.fsn)
                try:
                    mask = self.instrument.io.loadMask(header.maskname)
                except FileNotFoundError:
                    logger.warning(f'Invalid mask file "{header.maskname}". You might have to create a mask yourself.')
                    mask = np.ones_like(image, dtype=np.uint8)
                uncertainty = np.empty_like(image)
                uncertainty[image > 0] = image[image > 0] ** 0.5
                uncertainty[image <= 0] = 1
                self.writeNeXus(image, uncertainty)
                # emit the raw image.
                exposure = Exposure(image, header, uncertainty, mask)
                if self.prefix == self.instrument.config['path']['prefixes']['crd']:
                    self.instrument.datareduction.submit(exposure)
                self.finished.emit(True, exposure)

    def onDetectorExposureStarted(self, starttime):
        """This method should be called when the detector has acknowledged the exposure command.
        In this method we initialize the timers.
        """
        self.command_ack_time = starttime
        assert self.status == ExposureState.Initializing
        if not self.index:
            # this is the first exposure
            self.status = ExposureState.Pending
            self.onExposureStarted()
        else:
            # pending time: exptime * index + expdelay * index
            self.status = ExposureState.Pending
            self.pendingtimer = self.startTimer(
                int(1000 * (self.exptime + self.expdelay) * self.index),
                QtCore.Qt.PreciseTimer)
        self.runningtimer = self.startTimer(
            int(1000 * ((self.exptime + self.expdelay) * self.index + self.exptime)),
            QtCore.Qt.PreciseTimer)
        self.waitforimagetimer = self.startTimer(
            int(1000 * ((self.exptime + self.expdelay) * self.index + self.exptime + self.imagetimeout)),
            QtCore.Qt.PreciseTimer)

    def onExposureStarted(self):
        assert self.status == ExposureState.Pending
        self.status = ExposureState.Running
        self.exposurestarted.emit()

    def onExposureFinished(self):
        assert self.status == ExposureState.Running
        self.imageloadtimer = self.startTimer(int(1000 * self.imageloadperiod), QtCore.Qt.PreciseTimer)
        self.status = ExposureState.WaitingForImage
        self.exposureended.emit()

    def stopExposure(self):
        """Stop the ongoing exposure

        This method does not talk to the detector: its job is to stop all the timers, to avoid waiting
        """
        if self.pendingtimer:
            self.killTimer(self.pendingtimer)
            self.pendingtimer = None
        if self.runningtimer:
            self.killTimer(self.runningtimer)
            self.runningtimer = None
        if self.waitforimagetimer:
            self.killTimer(self.waitforimagetimer)
            self.waitforimagetimer = None
        if self.imageloadtimer:
            self.killTimer(self.imageloadtimer)
            self.imageloadtimer = None
        self.status = ExposureState.Stopped
        self.finished.emit(False, None)

    def createHeader(self) -> Header:
        sample: Optional[Sample] = self.instrument.samplestore.currentSample()
        data = {
            'fsn': self.fsn,
            'filename': os.path.abspath(
                os.path.join(
                    self.instrument.config['path']['directories']['param'], self.prefix,
                    self.instrument.io.formatFileName(self.prefix, self.fsn, '.pickle'))),
            'exposure': {
                'fsn': self.fsn,
                'prefix': self.prefix,
                'exptime': self.exptime,
                'monitor': self.exptime,
                'startdate': datetime.datetime.fromtimestamp(time.time() - time.monotonic() + self.starttime),
                'date': datetime.datetime.now(),
                'enddate': datetime.datetime.now(),
            },
            'geometry': self.instrument.geometry.getHeaderEntry(),
            'sample': sample.todict() if sample is not None else {},
            'motors': self.instrument.motors.getHeaderEntry(),
            'devices': {dev.name: dev.toDict() for dev in self.instrument.devicemanager if dev.isOnline()},
            'environment': {},
            'accounting': {'projectid': self.instrument.projects.project().projectid,
                           'operator': self.instrument.auth.username(),
                           'projectname': self.instrument.projects.project().title,
                           'proposer': self.instrument.projects.project().proposer},
        }
        # devices
        for dev in self.instrument.devicemanager:
            if not dev.isOnline():
                continue
            data['devices'][dev.name]['devicetype'] = dev.devicetype.value
            data['devices'][dev.name]['deviceclass'] = dev.devicename
        # environment
        try:
            vac = self.instrument.devicemanager.vacuum()
            data['environment']['vacuum_pressure'] = vac.pressure()
        except (KeyError, IndexError, DeviceFrontend.DeviceError):
            data['environment']['vacuum_pressure'] = 0.0001
        try:
            temp = self.instrument.devicemanager.temperature()
            data['environment']['temperature'] = temp.temperature()
        except (KeyError, IndexError, DeviceFrontend.DeviceError):
            data['environment']['temperature'] = np.nan
        # sensors
        data['sensors'] = {s.name: s.__getstate__() for s in self.instrument.sensors}
        # adjust truedistance
        if sample is not None:
            data['geometry']['truedistance'] = data['geometry']['dist_sample_det'] - data['sample']['distminus.val']
            data['geometry']['truedistance.err'] = (data['geometry']['dist_sample_det.err'] ** 2 + data['sample'][
                'distminus.err'] ** 2) ** 0.5
        if (sample is not None) and (sample.maskoverride is not None):
            data['geometry']['mask'] = sample.maskoverride
        if self.maskoverride is not None:
            # global mask override takes precedence
            data['geometry']['mask'] = self.maskoverride
        # Save the pickle file
        folder, filename = os.path.split(data['filename'])
        os.makedirs(folder, exist_ok=True)
        with open(data['filename'], 'wb') as f:
            pickle.dump(data, f)
        return Header(datadict=data)

    def writeNeXus(self, img: np.ndarray, unc: np.ndarray):
        if self.h5 is None:
            return
        grp = self.h5.require_group(f'{self.prefix}_{self.fsn:05d}')
        grp.attrs['NX_class'] = 'NXentry'
        # the instrument state has already been written, no need to call self.instrument.toNeXus() again.
        instgroup = [g for g in grp if g.attrs['NX_class'] == 'NXinstrument'][0]
        detectorgroup: h5py.Group = [g for g in instgroup if instgroup[g].attrs['NX_class'] == 'NXdetector'][0]
        detectorgroup.create_dataset('data', data=img)
        detectorgroup.create_dataset('data_errors', data=unc)
<commit_msg>Bug fixing in NeXus writing<commit_after># coding: utf-8
"""ExposureTask: a class representing an ongoing exposure with the detector"""
import datetime
import enum
import logging
import os
import pickle
import time
from typing import Optional

import h5py
import numpy as np
from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal as Signal

from ....dataclasses.exposure import Exposure
from ....dataclasses.header import Header
from ....dataclasses.sample import Sample
from ....devices.detector.pilatus.frontend import PilatusDetector
from ....devices.device.frontend import DeviceFrontend

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

class ExposureState(enum.Enum):
    Initializing = enum.auto()  # the detector is being initialized by the Exposer
    Pending = enum.auto()  # another image is being collected, wait for our turn
    Running = enum.auto()  # this image is being collected
    WaitingForImage = enum.auto()  # collection done, trying to load the image file from disk
    Finished = enum.auto()  # finished successfully, image have been loaded
    TimedOut = enum.auto()  # finished unsuccessfully, image file could not be found
    Stopped = enum.auto()  # finished, stopped on external request

class ExposureTask(QtCore.QObject):
    """Representation of a scheduled/running exposure

    The life of an exposure is the following, reflected by the `status` variable:
        - the exposure task is created in the "Initializing" state. This precedes the issuing of the start exposure
          command to the detector.
        - After the detector has acknowledged the exposure command, the exposure task goes into the "Running" state. If
          multiple exposures are requested, the first one will be "Running", the subsequent ones are "Pending".
        - "Pending" tasks become "Running" when all previous exposures have been done and the waiting times inbetween
          them are also elapsed. In this sense, the i-th exposure (i=1..) spends `exptime`*(i-1) + `expdelay`*(i-1) in
          the "Pending" state and finishes after i*`exptime` + (i-1)*`expdelay`.
        - When the exposure time has elapsed (on the clock of the computer, i.e. no interaction is needed with the
          detector hardware), the state turns to "WaitingForImage". In this state the program tries periodically to load
          the image file from the disk.
        - If the image file is found in the preferred timeout interval, the status gets to "Finished". This is success.
        - If the image file is not found even after the timeout has been elapsed, the status will be "TimedOut".

    The following signals are defined:

        - `exposurestarted`: emitted at the actual start of the exposure (estimated using the clock)
        - `exposureended`: emitted at the actual end of the exposure
        - `finished`: emitted when the image has been loaded / the image loading timeout has been spent

    :ivar prefix: file name prefix, e.g. 'crd', 'tst', 'scn', 'tra' etc.
    :type prefix: str
    :ivar fsn: file sequence number of this exposure
    :type fsn: int
    :ivar command_issue_time: the timestamp (a la time.monotonic()) when the detector was started
    :type command_issue_time: float
    :ivar command_ack_time: the timestamp (a la time.monotonic()) when the detector acknowledged the start command
    :type command_ack_time: float
    :ivar exptime: time of a single exposure (sec)
    :type exptime: float
    :ivar expdelay: delay between two subsequent exposures in a multi-exposure series (sec)
    :type expdelay: float
    :ivar imagetimeout: time before giving up on reading a finished image (sec)
    :type imagetimeout: float
    :ivar index: the 0-based index of this image in a multi-frame exposure
    :type index: int
    :ivar maskoverride: use a different mask
    :type maskoverride: str or None
    """
    # all times are from time.monotonic()
    prefix: str
    fsn: int
    firstfsn: int
    command_ack_time: Optional[float] = None  # when the detector backend process replied to the expose command
    exptime: float  # exposure time
    expdelay: float  # delay between exposures
    imagetimeout: float = 2.0  # timeout for waiting for the image.
    index: int  # 0-based index of this image in a multiple exposure sequence
    maskoverride: Optional[str] = None
    status: ExposureState = ExposureState.Initializing
    finished = Signal(bool, object)
    exposurestarted = Signal()
    exposureended = Signal()
    pendingtimer: Optional[int] = None
    runningtimer: Optional[int] = None
    waitforimagetimer: Optional[int] = None
    imageloadtimer: Optional[int] = None
    imageloadperiod: float = 0.1
    instrument: "Instrument"
    detector: PilatusDetector
    h5: Optional[h5py.File] = None

    def __init__(self, instrument: "Instrument", detector: PilatusDetector, prefix: str, fsn: int, index: int,
                 exptime: float, expdelay: float, maskoverride: Optional[str] = None, writenexus: bool = False):
        super().__init__()
        self.prefix = prefix
        self.fsn = fsn
        self.index = index
        self.exptime = exptime
        self.expdelay = expdelay
        self.exptime = exptime
        self.maskoverride = maskoverride
        self.status = ExposureState.Initializing
        self.instrument = instrument
        self.detector = detector
        self.writenexus = writenexus
        if writenexus:
            targetdir = os.path.join(self.instrument.io.getSubDir('nexus'), prefix)
            os.makedirs(targetdir, exist_ok=True)
            self.h5 = h5py.File(
                os.path.join(targetdir, self.instrument.io.formatFileName(prefix, fsn, '.nxs')), 'w',
                libver='latest')
            grp = self.h5.require_group(f'{prefix}_{fsn:05d}')
            grp.attrs['NX_class'] = 'NXentry'
            self.instrument.toNeXus(grp)

    @property
    def starttime(self):
        """expected start time of this image"""
        return self.command_ack_time + self.index * (self.exptime + self.expdelay)

    @property
    def endtime(self):
        """expected end time of this image"""
        return self.starttime + self.exptime

    def timerEvent(self, event: QtCore.QTimerEvent) -> None:
        if (event.timerId() == self.pendingtimer) and (self.status == ExposureState.Pending):
            # the exposure is supposedly started
            self.onExposureStarted()
            self.killTimer(self.pendingtimer)
            self.pendingtimer = None
        elif (event.timerId() == self.runningtimer) and (self.status == ExposureState.Running):
            # the exposure is supposedly ended
            self.onExposureFinished()
            self.killTimer(self.runningtimer)
            self.runningtimer = None
        elif (event.timerId() == self.waitforimagetimer) and (self.status == ExposureState.WaitingForImage):
            # image waiting timeout spent
            self.killTimer(self.waitforimagetimer)
            self.waitforimagetimer = None
            self.status = ExposureState.TimedOut
            self.finished.emit(False, None)
        elif (event.timerId() == self.imageloadtimer) and (self.status == ExposureState.WaitingForImage):
            # try to load the image
            try:
                image = self.instrument.io.loadCBF(self.prefix, self.fsn, check_local=False)
            except FileNotFoundError:
                # the file is not there (yet?). Wait until timeout
                pass
            else:
                # the file has been found. Kill the timers
                self.killTimer(self.waitforimagetimer)
                self.killTimer(self.imageloadtimer)
                self.waitforimagetimer = None
                self.imageloadtimer = None
                self.status = ExposureState.Finished
                # construct the metadata
                header = self.createHeader()
                self.instrument.io.imageReceived(self.prefix, self.fsn)
                try:
                    mask = self.instrument.io.loadMask(header.maskname)
                except FileNotFoundError:
                    logger.warning(f'Invalid mask file "{header.maskname}". You might have to create a mask yourself.')
                    mask = np.ones_like(image, dtype=np.uint8)
                uncertainty = np.empty_like(image)
                uncertainty[image > 0] = image[image > 0] ** 0.5
                uncertainty[image <= 0] = 1
                self.writeNeXus(image, uncertainty)
                # emit the raw image.
                exposure = Exposure(image, header, uncertainty, mask)
                if self.prefix == self.instrument.config['path']['prefixes']['crd']:
                    self.instrument.datareduction.submit(exposure)
                self.finished.emit(True, exposure)

    def onDetectorExposureStarted(self, starttime):
        """This method should be called when the detector has acknowledged the exposure command.
        In this method we initialize the timers.
        """
        self.command_ack_time = starttime
        assert self.status == ExposureState.Initializing
        if not self.index:
            # this is the first exposure
            self.status = ExposureState.Pending
            self.onExposureStarted()
        else:
            # pending time: exptime * index + expdelay * index
            self.status = ExposureState.Pending
            self.pendingtimer = self.startTimer(
                int(1000 * (self.exptime + self.expdelay) * self.index),
                QtCore.Qt.PreciseTimer)
        self.runningtimer = self.startTimer(
            int(1000 * ((self.exptime + self.expdelay) * self.index + self.exptime)),
            QtCore.Qt.PreciseTimer)
        self.waitforimagetimer = self.startTimer(
            int(1000 * ((self.exptime + self.expdelay) * self.index + self.exptime + self.imagetimeout)),
            QtCore.Qt.PreciseTimer)

    def onExposureStarted(self):
        assert self.status == ExposureState.Pending
        self.status = ExposureState.Running
        self.exposurestarted.emit()

    def onExposureFinished(self):
        assert self.status == ExposureState.Running
        self.imageloadtimer = self.startTimer(int(1000 * self.imageloadperiod), QtCore.Qt.PreciseTimer)
        self.status = ExposureState.WaitingForImage
        self.exposureended.emit()

    def stopExposure(self):
        """Stop the ongoing exposure

        This method does not talk to the detector: its job is to stop all the timers, to avoid waiting
        """
        if self.pendingtimer:
            self.killTimer(self.pendingtimer)
            self.pendingtimer = None
        if self.runningtimer:
            self.killTimer(self.runningtimer)
            self.runningtimer = None
        if self.waitforimagetimer:
            self.killTimer(self.waitforimagetimer)
            self.waitforimagetimer = None
        if self.imageloadtimer:
            self.killTimer(self.imageloadtimer)
            self.imageloadtimer = None
        self.status = ExposureState.Stopped
        self.finished.emit(False, None)

    def createHeader(self) -> Header:
        sample: Optional[Sample] = self.instrument.samplestore.currentSample()
        data = {
            'fsn': self.fsn,
            'filename': os.path.abspath(
                os.path.join(
                    self.instrument.config['path']['directories']['param'], self.prefix,
                    self.instrument.io.formatFileName(self.prefix, self.fsn, '.pickle'))),
            'exposure': {
                'fsn': self.fsn,
                'prefix': self.prefix,
                'exptime': self.exptime,
                'monitor': self.exptime,
                'startdate': datetime.datetime.fromtimestamp(time.time() - time.monotonic() + self.starttime),
                'date': datetime.datetime.now(),
                'enddate': datetime.datetime.now(),
            },
            'geometry': self.instrument.geometry.getHeaderEntry(),
            'sample': sample.todict() if sample is not None else {},
            'motors': self.instrument.motors.getHeaderEntry(),
            'devices': {dev.name: dev.toDict() for dev in self.instrument.devicemanager if dev.isOnline()},
            'environment': {},
            'accounting': {'projectid': self.instrument.projects.project().projectid,
                           'operator': self.instrument.auth.username(),
                           'projectname': self.instrument.projects.project().title,
                           'proposer': self.instrument.projects.project().proposer},
        }
        # devices
        for dev in self.instrument.devicemanager:
            if not dev.isOnline():
                continue
            data['devices'][dev.name]['devicetype'] = dev.devicetype.value
            data['devices'][dev.name]['deviceclass'] = dev.devicename
        # environment
        try:
            vac = self.instrument.devicemanager.vacuum()
            data['environment']['vacuum_pressure'] = vac.pressure()
        except (KeyError, IndexError, DeviceFrontend.DeviceError):
            data['environment']['vacuum_pressure'] = 0.0001
        try:
            temp = self.instrument.devicemanager.temperature()
            data['environment']['temperature'] = temp.temperature()
        except (KeyError, IndexError, DeviceFrontend.DeviceError):
            data['environment']['temperature'] = np.nan
        # sensors
        data['sensors'] = {s.name: s.__getstate__() for s in self.instrument.sensors}
        # adjust truedistance
        if sample is not None:
            data['geometry']['truedistance'] = data['geometry']['dist_sample_det'] - data['sample']['distminus.val']
            data['geometry']['truedistance.err'] = (data['geometry']['dist_sample_det.err'] ** 2 + data['sample'][
                'distminus.err'] ** 2) ** 0.5
        if (sample is not None) and (sample.maskoverride is not None):
            data['geometry']['mask'] = sample.maskoverride
        if self.maskoverride is not None:
            # global mask override takes precedence
            data['geometry']['mask'] = self.maskoverride
        # Save the pickle file
        folder, filename = os.path.split(data['filename'])
        os.makedirs(folder, exist_ok=True)
        with open(data['filename'], 'wb') as f:
            pickle.dump(data, f)
        return Header(datadict=data)

    def writeNeXus(self, img: np.ndarray, unc: np.ndarray):
        if self.h5 is None:
            return
        grp = self.h5.require_group(f'{self.prefix}_{self.fsn:05d}')
        grp.attrs['NX_class'] = 'NXentry'
        # the instrument state has already been written, no need to call self.instrument.toNeXus() again.
        instgroup = [g for g in grp if grp[g].attrs['NX_class'] == 'NXinstrument'][0]
        detectorgroup: h5py.Group = [g for g in instgroup if instgroup[g].attrs['NX_class'] == 'NXdetector'][0]
        detectorgroup.create_dataset('data', data=img)
        detectorgroup.create_dataset('data_errors', data=unc)
<|endoftext|>