<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Simple VTK Viewer.

Example:

$ viewer.py -f head.vtk
"""
from optparse import OptionParser
import sys
import vessel_cut

from PyQt4 import QtCore, QtGui
from PyQt4 import *
from PyQt4.QtGui import *
from PyQt4.QtCore import *

from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from vtk import *
from Tkinter import *
plane = vtk.vtkPlane()
normal = None
coordinates = None
planew = None

class normal_and_coordinates():

    def set_normal(self):
        return normal

    def set_coordinates(self):
        return coordinates

class QVTKViewer(QDialog):
    """
    Simple VTK Viewer.
    """

    def __init__(self, vtk_filename):

        def callback(button):
            print button

        def Cutter(obj, event):
            global plane, selectActor
            obj.GetPlane(plane)

        def Plane():
            planeWidget = vtk.vtkImplicitPlaneWidget()
            planeWidget.SetInteractor(iren)
            planeWidget.SetPlaceFactor(1.5)
            planeWidget.SetInput(surface.GetOutput())
            planeWidget.PlaceWidget()
            planeWidget.TubingOff()
            planeWidget.OutsideBoundsOff()
            planeWidget.ScaleEnabledOff()
            planeWidget.OutlineTranslationOff()
            planeWidget.AddObserver("InteractionEvent", Cutter)

            planeWidget.On()
            window.setLayout(grid)

            self.planew = planeWidget

            window.show()
            iren.Initialize()
            renWin.Render()
            iren.Start()

        def liver_view():
            print('Zobrazuji liver')
            vessel_cut.View('liver')

        def vein_view():
            print('Zobrazuji vein')
            vessel_cut.View('porta')

        def liver_cut():
            global normal
            global coordinates
            normal = self.planew.GetNormal()
            coordinates = self.planew.GetOrigin()
            print(normal)
            print(coordinates)

        """
        Initiate Viwer

        Parameters
        ----------
        vtk_filename : str
            Input VTK filename
        """

        # Renderer and InteractionStyle
        ren = vtk.vtkRenderer()
        renWin = vtk.vtkRenderWindow()
        renWin.AddRenderer(ren)

        iren = vtk.vtkRenderWindowInteractor()
        iren.SetRenderWindow(renWin)
        iren.SetInteractorStyle(MyInteractorStyle())

        # VTK file
        reader = vtk.vtkUnstructuredGridReader()
        reader.SetFileName(vtk_filename)
        reader.Update()

        # VTK surface
        surface=vtk.vtkDataSetSurfaceFilter()
        surface.SetInput(reader.GetOutput())
        surface.Update()

        # Cutter
        clipper = vtk.vtkClipPolyData()
        clipper.SetInput(surface.GetOutput())
        clipper.SetClipFunction(plane)
        #clipper.GenerateClipScalarsOn()
        clipper.GenerateClippedOutputOn()

        clipMapper = vtk.vtkPolyDataMapper()
        clipMapper.SetInput(clipper.GetOutput())

        backProp = vtk.vtkProperty()

        clipActor = vtk.vtkActor()
        clipActor.SetMapper(clipMapper)
        clipActor.GetProperty().SetColor(1,0,0)
        clipActor.SetBackfaceProperty(backProp)

        cutEdges = vtk.vtkCutter()
        cutEdges.SetInput(surface.GetOutput())
        cutEdges.SetCutFunction(plane)
        cutEdges.GenerateCutScalarsOn()

        cutStrips = vtk.vtkStripper()
        cutStrips.SetInput(cutEdges.GetOutput())
        cutStrips.Update()

        cutPoly = vtk.vtkPolyData()
        cutPoly.SetPoints(cutStrips.GetOutput().GetPoints())
        cutPoly.SetPolys(cutStrips.GetOutput().GetLines())

        cutTriangles = vtk.vtkTriangleFilter()
        cutTriangles.SetInput(cutPoly)

        cutMapper = vtk.vtkPolyDataMapper()
        cutMapper.SetInput(cutTriangles.GetOutput())

        cutActor = vtk.vtkActor()
        cutActor.SetMapper(cutMapper)
        cutActor.GetProperty().SetColor((1,0,0))

        mapper = vtk.vtkDataSetMapper()
        mapper.SetInput(clipper.GetClippedOutput())
        mapper.ScalarVisibilityOff()

        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().EdgeVisibilityOn()
        #sirka linek u objektu
        actor.GetProperty().SetLineWidth(0.1)
        actor.GetProperty().SetRepresentationToWireframe()
        ren.AddActor(clipActor)
        ren.AddActor(cutActor)
        ren.AddActor(actor)

        window = QtGui.QWidget()
        grid = QtGui.QGridLayout()

        # Button liver
        button_liver = QtGui.QPushButton()
        button_liver.setText(unicode('liver'))
        grid.addWidget(button_liver, 1, 0)
        window.connect(button_liver, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : liver'))
        button_liver.clicked.connect(liver_view)
        button_liver.show()

        # Button vein
        button_vein = QtGui.QPushButton()
        button_vein.setText(unicode('vein'))
        grid.addWidget(button_vein, 2, 0)
        window.connect(button_vein, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : vein'))
        button_liver.clicked.connect(vein_view)
        button_vein.show()

        # Button plane
        button_plane = QtGui.QPushButton()
        button_plane.setText(unicode('plane'))
        grid.addWidget(button_plane, 3, 0)
        window.connect(button_plane, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : plane'))
        button_plane.clicked.connect(Plane)
        button_plane.show()

        # Button cut
        button_cut = QtGui.QPushButton()
        button_cut.setText(unicode('cut'))
        grid.addWidget(button_cut, 4, 0)
        window.connect(button_cut, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : cut'))
        button_cut.clicked.connect(liver_cut)
        button_cut.show()

        window.setLayout(grid)
        window.show()

        # set interaction and Interaction style
        iren.Initialize()
        renWin.Render()
        iren.Start()

class MyInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
        def __init__(self,parent=None):
            self.AddObserver("LeftButtonPressEvent",self.LeftButtonPressEvent)
            self.AddObserver("RightButtonPressEvent",self.RightButtonPressEvent)

        def LeftButtonPressEvent(self,obj,event):
            print "Left Button pressed"
            self.Rotate()
            self.OnLeftButtonDown()

        def RightButtonPressEvent(self,obj,event):
            print "Right Button pressed"
            self.Pan()
            self.OnRightButtonDown()

        e = '%prog [options]\n' + __doc__.rstrip()
help = {
    'in_file': 'input VTK file with unstructured mesh',
}

def main():
    parser = OptionParser(description='Simple VTK Viewer')
    parser.add_option('-f','--filename', action='store',
                      dest='in_filename', default=None,
                      help=help['in_file'])
    (options, args) = parser.parse_args()

    if options.in_filename is None:
        raise IOError('No VTK data!')

    app = QApplication(sys.argv)
    viewer = QVTKViewer(options.in_filename)
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

<commit_msg>repair-vein button<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Simple VTK Viewer.

Example:

$ viewer.py -f head.vtk
"""
from optparse import OptionParser
import sys
import vessel_cut

from PyQt4 import QtCore, QtGui
from PyQt4 import *
from PyQt4.QtGui import *
from PyQt4.QtCore import *

from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from vtk import *
from Tkinter import *
plane = vtk.vtkPlane()
normal = None
coordinates = None
planew = None

class normal_and_coordinates():

    def set_normal(self):
        return normal

    def set_coordinates(self):
        return coordinates

class QVTKViewer(QDialog):
    """
    Simple VTK Viewer.
    """

    def __init__(self, vtk_filename):

        def callback(button):
            print button

        def Cutter(obj, event):
            global plane, selectActor
            obj.GetPlane(plane)

        def Plane():
            planeWidget = vtk.vtkImplicitPlaneWidget()
            planeWidget.SetInteractor(iren)
            planeWidget.SetPlaceFactor(1.5)
            planeWidget.SetInput(surface.GetOutput())
            planeWidget.PlaceWidget()
            planeWidget.TubingOff()
            planeWidget.OutsideBoundsOff()
            planeWidget.ScaleEnabledOff()
            planeWidget.OutlineTranslationOff()
            planeWidget.AddObserver("InteractionEvent", Cutter)

            planeWidget.On()
            window.setLayout(grid)

            self.planew = planeWidget

            window.show()
            iren.Initialize()
            renWin.Render()
            iren.Start()

        def liver_view():
            print('Zobrazuji liver')
            vessel_cut.View('liver')

        def vein_view():
            print('Zobrazuji vein')
            vessel_cut.View('porta')

        def liver_cut():
            global normal
            global coordinates
            normal = self.planew.GetNormal()
            coordinates = self.planew.GetOrigin()
            print(normal)
            print(coordinates)

        """
        Initiate Viwer

        Parameters
        ----------
        vtk_filename : str
            Input VTK filename
        """

        # Renderer and InteractionStyle
        ren = vtk.vtkRenderer()
        renWin = vtk.vtkRenderWindow()
        renWin.AddRenderer(ren)

        iren = vtk.vtkRenderWindowInteractor()
        iren.SetRenderWindow(renWin)
        iren.SetInteractorStyle(MyInteractorStyle())

        # VTK file
        reader = vtk.vtkUnstructuredGridReader()
        reader.SetFileName(vtk_filename)
        reader.Update()

        # VTK surface
        surface=vtk.vtkDataSetSurfaceFilter()
        surface.SetInput(reader.GetOutput())
        surface.Update()

        # Cutter
        clipper = vtk.vtkClipPolyData()
        clipper.SetInput(surface.GetOutput())
        clipper.SetClipFunction(plane)
        #clipper.GenerateClipScalarsOn()
        clipper.GenerateClippedOutputOn()

        clipMapper = vtk.vtkPolyDataMapper()
        clipMapper.SetInput(clipper.GetOutput())

        backProp = vtk.vtkProperty()

        clipActor = vtk.vtkActor()
        clipActor.SetMapper(clipMapper)
        clipActor.GetProperty().SetColor(1,0,0)
        clipActor.SetBackfaceProperty(backProp)

        cutEdges = vtk.vtkCutter()
        cutEdges.SetInput(surface.GetOutput())
        cutEdges.SetCutFunction(plane)
        cutEdges.GenerateCutScalarsOn()

        cutStrips = vtk.vtkStripper()
        cutStrips.SetInput(cutEdges.GetOutput())
        cutStrips.Update()

        cutPoly = vtk.vtkPolyData()
        cutPoly.SetPoints(cutStrips.GetOutput().GetPoints())
        cutPoly.SetPolys(cutStrips.GetOutput().GetLines())

        cutTriangles = vtk.vtkTriangleFilter()
        cutTriangles.SetInput(cutPoly)

        cutMapper = vtk.vtkPolyDataMapper()
        cutMapper.SetInput(cutTriangles.GetOutput())

        cutActor = vtk.vtkActor()
        cutActor.SetMapper(cutMapper)
        cutActor.GetProperty().SetColor((1,0,0))

        mapper = vtk.vtkDataSetMapper()
        mapper.SetInput(clipper.GetClippedOutput())
        mapper.ScalarVisibilityOff()

        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().EdgeVisibilityOn()
        #sirka linek u objektu
        actor.GetProperty().SetLineWidth(0.1)
        actor.GetProperty().SetRepresentationToWireframe()
        ren.AddActor(clipActor)
        ren.AddActor(cutActor)
        ren.AddActor(actor)

        window = QtGui.QWidget()
        grid = QtGui.QGridLayout()

        # Button liver
        button_liver = QtGui.QPushButton()
        button_liver.setText(unicode('liver'))
        grid.addWidget(button_liver, 1, 0)
        window.connect(button_liver, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : liver'))
        button_liver.clicked.connect(liver_view)
        button_liver.show()

        # Button vein
        button_vein = QtGui.QPushButton()
        button_vein.setText(unicode('vein'))
        grid.addWidget(button_vein, 2, 0)
        window.connect(button_vein, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : vein'))
        button_vein.clicked.connect(vein_view)
        button_vein.show()

        # Button plane
        button_plane = QtGui.QPushButton()
        button_plane.setText(unicode('plane'))
        grid.addWidget(button_plane, 3, 0)
        window.connect(button_plane, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : plane'))
        button_plane.clicked.connect(Plane)
        button_plane.show()

        # Button cut
        button_cut = QtGui.QPushButton()
        button_cut.setText(unicode('cut'))
        grid.addWidget(button_cut, 4, 0)
        window.connect(button_cut, QtCore.SIGNAL("clicked()"),(lambda y:lambda: callback(y) )('Stisknuto : cut'))
        button_cut.clicked.connect(liver_cut)
        button_cut.show()

        window.setLayout(grid)
        window.show()

        # set interaction and Interaction style
        iren.Initialize()
        renWin.Render()
        iren.Start()

class MyInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
        def __init__(self,parent=None):
            self.AddObserver("LeftButtonPressEvent",self.LeftButtonPressEvent)
            self.AddObserver("RightButtonPressEvent",self.RightButtonPressEvent)

        def LeftButtonPressEvent(self,obj,event):
            print "Left Button pressed"
            self.Rotate()
            self.OnLeftButtonDown()

        def RightButtonPressEvent(self,obj,event):
            print "Right Button pressed"
            self.Pan()
            self.OnRightButtonDown()

        e = '%prog [options]\n' + __doc__.rstrip()
help = {
    'in_file': 'input VTK file with unstructured mesh',
}

def main():
    parser = OptionParser(description='Simple VTK Viewer')
    parser.add_option('-f','--filename', action='store',
                      dest='in_filename', default=None,
                      help=help['in_file'])
    (options, args) = parser.parse_args()

    if options.in_filename is None:
        raise IOError('No VTK data!')

    app = QApplication(sys.argv)
    viewer = QVTKViewer(options.in_filename)
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Main file of Kuray. Execute it to use the application. """
import numpy as np
import matplotlib.pyplot as plt
import pyaudio

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

def generate_sweep(length):
    """ Generate sweep with `length` number of samples. """
    amp = 2**15 - 1
    f_start = 30.0
    f_stop = 20000
    phi = 0.0
    d_phi = 2*np.pi*f_start/RATE

    sweep = np.zeros(length)
    for i in range(length):
        sweep[i] = amp*np.sin(phi)
        phi += d_phi
        d_phi *= 2**(np.log2(f_stop - f_start) / length)

    sweep = np.int16(sweep)
    return sweep

def main():
    """ Main function; acts as entry point for Kuray. """
    # Initialize PortAudio
    port_audio = pyaudio.PyAudio()

    stream = port_audio.open(format = FORMAT, channels = CHANNELS, rate = RATE,
                             input = True, output = True,
                             frames_per_buffer = CHUNK)

    length = 2**18
    sweep = generate_sweep(length)

    stream.write(sweep)
    answer = []
    for _ in range(length//CHUNK):
        data = stream.read(CHUNK)
        answer = np.append(answer, np.fromstring(data, 'Int16'))

    fft_input = np.fft.fft(sweep)
    fft_output = np.fft.fft(answer)
    transfer_function = fft_output / fft_input

    plt.subplot(2, 1, 1)
    plt.plot(np.abs(transfer_function))
    plt.subplot(2, 1, 2)
    plt.plot(np.angle(transfer_function, deg=True))
    plt.show()

if __name__ == "__main__":
    main()
<commit_msg>Threw together a GUI, going to clean it up later<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Main file of Kuray. Execute it to use the application. """
import numpy as np
import matplotlib as mpl
mpl.rcParams['backend.qt4'] = 'PySide'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import pyaudio
import PySide.QtGui as QtGui
import PySide.QtCore as QtCore
import sys

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

class Gui(QtGui.QMainWindow):
    """ Gui class for the main window. """

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setWindowTitle("Kuray")
        self._create_main_frame()

    def _on_measure(self):
        """ Start measurement. """
        # Initialize PortAudio
        port_audio = pyaudio.PyAudio()

        stream = port_audio.open(format=FORMAT, channels=CHANNELS, rate=RATE,
                                 input=True, output=True,
                                 frames_per_buffer = CHUNK)

        length = 2**18
        sweep = generate_sweep(length)

        stream.write(sweep)
        answer = []
        for _ in range(length//CHUNK):
            data = stream.read(CHUNK)
            answer = np.append(answer, np.fromstring(data, 'Int16'))

        fft_input = np.fft.fft(sweep)
        fft_output = np.fft.fft(answer)
        transfer_function = fft_output / fft_input

        # No need to plot this much data, resolution is too low anyway
        tf_chunked = transfer_function[0::10]
        self.axes1.semilogx(np.linspace(30, 2e4, len(tf_chunked)),
                            np.log10(np.abs(tf_chunked)))
        self.axes2.semilogx(np.linspace(30, 2e4, len(tf_chunked)),
                        np.angle(tf_chunked, deg=True))

        tick_frequencies = [31, 62, 125, 250, 500, 1000,
                            2000, 4000, 8000, 16000]
        ticklabel_frequencies = ['31', '62', '125', '250', '500', '1k',
                                 '2k', '4k', '8k', '16k']
        self.axes1.set_xticks(tick_frequencies)
        self.axes2.set_xticks(tick_frequencies)
        self.axes1.set_xticklabels(ticklabel_frequencies)
        self.axes2.set_xticklabels(ticklabel_frequencies)
        self.canvas.draw()

    def _create_main_frame(self):
        """ Create main frame within the main window. """
        self.main_frame = QtGui.QWidget()
        self.fig = mpl.figure.Figure((5.0, 4.0))
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)

        self.measure_button = QtGui.QPushButton("&Measure")
        self.connect(self.measure_button, QtCore.SIGNAL('clicked()'),
                     self._on_measure)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.measure_button)

        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)

        self.axes1 = self.fig.add_subplot(2, 1, 1)
        self.axes2 = self.fig.add_subplot(2, 1, 2)
        self.line1, = self.axes1.semilogx([], [])
        self.line2, = self.axes2.semilogx([], [])
        self.axes1.grid(True)
        self.axes2.grid(True)
        self.axes1.set_xlim(30, 2e4)
        self.axes2.set_xlim(30, 2e4)
        tick_frequencies = [31, 62, 125, 250, 500, 1000,
                            2000, 4000, 8000, 16000]
        ticklabel_frequencies = ['31', '62', '125', '250', '500', '1k',
                                 '2k', '4k', '8k', '16k']
        self.axes1.set_xticks(tick_frequencies)
        self.axes2.set_xticks(tick_frequencies)
        self.axes1.set_xticklabels(ticklabel_frequencies)
        self.axes2.set_xticklabels(ticklabel_frequencies)

        self.canvas.draw()

def generate_sweep(length):
    """ Generate sweep with `length` number of samples. """
    amp = 2**15 - 1
    f_start = 30.0
    f_stop = 20000
    phi = 0.0
    d_phi = 2*np.pi*f_start/RATE

    sweep = np.zeros(length)
    for i in range(length):
        sweep[i] = amp*np.sin(phi)
        phi += d_phi
        d_phi *= 2**(np.log2(f_stop - f_start) / length)

    sweep = np.int16(sweep)
    return sweep

def main():
    """ Main function; acts as entry point for Kuray. """
    app = QtGui.QApplication(sys.argv)
    gui = Gui()
    gui.show()
    app.exec_()

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>from enum import Enum
import logging
from collections import deque

from ply.lex import Lexer, LexToken

from process import State, CatCode

logger = logging.getLogger(__name__)

tokens = (
    'CONTROL_SEQUENCE',
    'SINGLE_CHAR_CONTROL_SEQUENCE',

    'PREFIX',

    'SPACE',
    'LEFT_BRACE',
    'RIGHT_BRACE',
    'ACTIVE_CHARACTER',

    'BALANCED_TEXT',

    'CHARACTER',

    # Internal tokens.
    'CHAR_DEF_TOKEN',
    'MATH_CHAR_DEF_TOKEN',
    'COUNT_DEF_TOKEN',
)

primitive_control_sequences_map = {
    'catcode': 'CAT_CODE',
    'mathcode': 'MATH_CODE',
    'uccode': 'UPPER_CASE_CODE',
    'lccode': 'LOWER_CASE_CODE',
    'sfcode': 'SPACE_FACTOR_CODE',
    'delcode': 'DELIMITER_CODE',

    'chardef': 'CHAR_DEF',
    'mathchardef': 'MATH_CHAR_DEF',
    'countdef': 'COUNT_DEF',

    'par': 'PAR',
    'count': 'COUNT',
    'def': 'DEF',
    'message': 'MESSAGE',
    'relax': 'RELAX',
}

category_map = {
    CatCode.space: 'SPACE',
    CatCode.begin_group: 'LEFT_BRACE',
    CatCode.end_group: 'RIGHT_BRACE',
    CatCode.active: 'ACTIVE_CHARACTER',
}

literals_map = {
    ('=', CatCode.other): 'EQUALS',
    ('+', CatCode.other): 'PLUS_SIGN',
    ('-', CatCode.other): 'MINUS_SIGN',

    ('0', CatCode.other): 'ZERO',
    ('1', CatCode.other): 'ONE',
    ('2', CatCode.other): 'TWO',
    ('3', CatCode.other): 'THREE',
    ('4', CatCode.other): 'FOUR',
    ('5', CatCode.other): 'FIVE',
    ('6', CatCode.other): 'SIX',
    ('7', CatCode.other): 'SEVEN',
    ('8', CatCode.other): 'EIGHT',
    ('9', CatCode.other): 'NINE',
    ('A', CatCode.other): 'A',
    ('B', CatCode.other): 'B',
    ('C', CatCode.other): 'C',
    ('D', CatCode.other): 'D',
    ('E', CatCode.other): 'E',
    ('F', CatCode.other): 'F',
    ('A', CatCode.letter): 'A',
    ('B', CatCode.letter): 'B',
    ('C', CatCode.letter): 'C',
    ('D', CatCode.letter): 'D',
    ('E', CatCode.letter): 'E',
    ('F', CatCode.letter): 'F',

    ('\'', CatCode.other): 'SINGLE_QUOTE',
    ('"', CatCode.other): 'DOUBLE_QUOTE',
    ('`', CatCode.other): 'BACKTICK',
}

short_hand_def_token_map = {
    'chardef_token': 'CHAR_DEF_TOKEN',
    'mathchardef_token': 'MATH_CHAR_DEF_TOKEN',
    'countdef_token': 'COUNT_DEF_TOKEN',
}

tokens += tuple(set(literals_map.values()))
tokens += tuple(set(primitive_control_sequences_map.values()))

read_control_sequence_name_tokens = (
    'chardef',
    'mathchardef',
    'countdef',
    'def',
)

class LexMode(Enum):
    expand = 1
    read_balanced_text = 2
    no_expand = 3

class PLYLexer(Lexer):

    def __init__(self):
        self.lex_mode = LexMode.expand

    def input(self, chars):
        self.state = State(chars)
        self.state_tokens = self.state.get_tokens()
        self.tokens_stack = deque()

    def expand_control_sequence(self, name):
        return self.state.control_sequences[name]

    def fetch_state_tokens_in_balanced_text(self):
        brace_counter = 1
        state_tokens = []
        while True:
            state_token = next(self.state_tokens)
            if state_token['type'] == 'char_cat_pair':
                char, cat = state_token['char'], state_token['cat']
                if cat == CatCode.begin_group:
                    brace_counter += 1
                elif cat == CatCode.end_group:
                    brace_counter -= 1
                if brace_counter == 0:
                    break
            state_tokens.append(state_token)
        return state_tokens

    def fetch_state_token_tokens(self):
        if self.lex_mode == LexMode.read_balanced_text:
            state_tokens = self.fetch_state_tokens_in_balanced_text()
            token = PLYToken(type_='BALANCED_TEXT', value=state_tokens)
            self.lex_mode = LexMode.expand
            return [token]
        else:
            state_token = next(self.state_tokens)
            return self.state_token_tokens(state_token)

    def fetch_state_token_tokens_no_expand(self):
        '''
        Fetch a single state token, in no-expand lex mode, and convert it into
        its terminal tokens.
        '''
        old_lex_mode = self.lex_mode
        self.lex_mode = LexMode.no_expand
        tokens = self.fetch_state_token_tokens()
        self.lex_mode = old_lex_mode
        return tokens

    def state_token_tokens(self, state_token):
        '''
        Converts a single state token into one or more terminal tokens.
        One important case where one state token produces many terminal tokens,
        is when the state token is a macro call, which is expanded into the
        stored state tokens.
        '''
        tokens = []
        if state_token['type'] == 'control_sequence':
            name = state_token['name']
            if self.lex_mode == LexMode.no_expand:
                if len(name) == 1:
                    type_ = 'SINGLE_CHAR_CONTROL_SEQUENCE'
                else:
                    type_ = 'CONTROL_SEQUENCE'
                tokens.append(PLYToken(type_=type_, value=state_token))
            elif name in self.state.control_sequences:
                control_sequence_state_tokens = self.expand_control_sequence(name)
                for cs_state_token in control_sequence_state_tokens:
                    cs_terminal_tokens = self.state_token_tokens(cs_state_token)
                    tokens.extend(cs_terminal_tokens)
            elif name in primitive_control_sequences_map:
                token_type = primitive_control_sequences_map[name]
                tokens.append(PLYToken(type_=token_type, value=state_token))
                if name in read_control_sequence_name_tokens:
                    next_tokens = self.fetch_state_token_tokens_no_expand()
                    assert len(next_tokens) == 1
                    tokens.extend(next_tokens)
            elif name in ('global', 'long', 'outer'):
                tokens.append(PLYToken(type_='PREFIX', value=state_token))
            else:
                import pdb; pdb.set_trace()
        elif state_token['type'] == 'char_cat_pair':
            char, cat = state_token['char'], state_token['cat']
            if cat in (CatCode.letter, CatCode.other):
                if (char, cat) in literals_map:
                    type_ = literals_map[(char, cat)]
                else:
                    type_ = 'CHARACTER'
            elif cat in category_map:
                type_ = category_map[cat]
            else:
                import pdb; pdb.set_trace()
            token = PLYToken(type_, value=state_token)
            tokens.append(token)
            # TODO: this will probably break when using backticks for
            # open-quotes.
            # Maybe move this to parse rule, at seen_BACKTICK?
            if type_ == 'BACKTICK':
                next_tokens = self.fetch_state_token_tokens_no_expand()
                assert len(next_tokens) == 1
                tokens.extend(next_tokens)
            logger.info(token)
        elif state_token['type'] in short_hand_def_token_map:
            type_ = short_hand_def_token_map[state_token['type']]
            terminal_token = PLYToken(type_=type_, value=state_token['value'])
            tokens.append(terminal_token)
        else:
            import pdb; pdb.set_trace()
        return tokens

    def token(self):
        if not self.tokens_stack:
            try:
                tokens = self.fetch_state_token_tokens()
            except StopIteration:
                return
            self.tokens_stack.extend(tokens)
        token = self.tokens_stack.popleft()
        return token

class PLYToken(LexToken):

    def __init__(self, type_, value):
        self.type = type_
        self.value = value
        self.lineno = None
        self.lexpos = None

    def __repr__(self):
        return "<Token: %r %r>" % (self.type, self.value)

    def __str__(self):
        return self.__repr__()
<commit_msg>Split up lexer methods a bit<commit_after>from enum import Enum
import logging
from collections import deque

from ply.lex import Lexer, LexToken

from process import State, CatCode

logger = logging.getLogger(__name__)

tokens = (
    'CONTROL_SEQUENCE',
    'SINGLE_CHAR_CONTROL_SEQUENCE',

    'PREFIX',

    'SPACE',
    'LEFT_BRACE',
    'RIGHT_BRACE',
    'ACTIVE_CHARACTER',

    'BALANCED_TEXT',

    'CHARACTER',

    # Internal tokens.
    'CHAR_DEF_TOKEN',
    'MATH_CHAR_DEF_TOKEN',
    'COUNT_DEF_TOKEN',
)

primitive_control_sequences_map = {
    'catcode': 'CAT_CODE',
    'mathcode': 'MATH_CODE',
    'uccode': 'UPPER_CASE_CODE',
    'lccode': 'LOWER_CASE_CODE',
    'sfcode': 'SPACE_FACTOR_CODE',
    'delcode': 'DELIMITER_CODE',

    'chardef': 'CHAR_DEF',
    'mathchardef': 'MATH_CHAR_DEF',
    'countdef': 'COUNT_DEF',

    'par': 'PAR',
    'count': 'COUNT',
    'def': 'DEF',
    'message': 'MESSAGE',
    'relax': 'RELAX',
}

category_map = {
    CatCode.space: 'SPACE',
    CatCode.begin_group: 'LEFT_BRACE',
    CatCode.end_group: 'RIGHT_BRACE',
    CatCode.active: 'ACTIVE_CHARACTER',
}

literals_map = {
    ('=', CatCode.other): 'EQUALS',
    ('+', CatCode.other): 'PLUS_SIGN',
    ('-', CatCode.other): 'MINUS_SIGN',

    ('0', CatCode.other): 'ZERO',
    ('1', CatCode.other): 'ONE',
    ('2', CatCode.other): 'TWO',
    ('3', CatCode.other): 'THREE',
    ('4', CatCode.other): 'FOUR',
    ('5', CatCode.other): 'FIVE',
    ('6', CatCode.other): 'SIX',
    ('7', CatCode.other): 'SEVEN',
    ('8', CatCode.other): 'EIGHT',
    ('9', CatCode.other): 'NINE',
    ('A', CatCode.other): 'A',
    ('B', CatCode.other): 'B',
    ('C', CatCode.other): 'C',
    ('D', CatCode.other): 'D',
    ('E', CatCode.other): 'E',
    ('F', CatCode.other): 'F',
    ('A', CatCode.letter): 'A',
    ('B', CatCode.letter): 'B',
    ('C', CatCode.letter): 'C',
    ('D', CatCode.letter): 'D',
    ('E', CatCode.letter): 'E',
    ('F', CatCode.letter): 'F',

    ('\'', CatCode.other): 'SINGLE_QUOTE',
    ('"', CatCode.other): 'DOUBLE_QUOTE',
    ('`', CatCode.other): 'BACKTICK',
}

short_hand_def_token_map = {
    'chardef_token': 'CHAR_DEF_TOKEN',
    'mathchardef_token': 'MATH_CHAR_DEF_TOKEN',
    'countdef_token': 'COUNT_DEF_TOKEN',
}

tokens += tuple(set(literals_map.values()))
tokens += tuple(set(primitive_control_sequences_map.values()))

read_control_sequence_name_tokens = (
    'chardef',
    'mathchardef',
    'countdef',
    'def',
)

class LexMode(Enum):
    expand = 1
    read_balanced_text = 2
    no_expand = 3

class PLYLexer(Lexer):

    def __init__(self):
        self.lex_mode = LexMode.expand

    def input(self, chars):
        self.state = State(chars)
        self.state_tokens = self.state.get_tokens()
        self.tokens_stack = deque()

    def expand_control_sequence(self, name):
        return self.state.control_sequences[name]

    def fetch_state_tokens_in_balanced_text(self):
        brace_counter = 1
        state_tokens = []
        while True:
            state_token = next(self.state_tokens)
            if state_token['type'] == 'char_cat_pair':
                char, cat = state_token['char'], state_token['cat']
                if cat == CatCode.begin_group:
                    brace_counter += 1
                elif cat == CatCode.end_group:
                    brace_counter -= 1
                if brace_counter == 0:
                    break
            state_tokens.append(state_token)
        return state_tokens

    def fetch_state_token_tokens(self):
        if self.lex_mode == LexMode.read_balanced_text:
            state_tokens = self.fetch_state_tokens_in_balanced_text()
            token = PLYToken(type_='BALANCED_TEXT', value=state_tokens)
            self.lex_mode = LexMode.expand
            return [token]
        else:
            state_token = next(self.state_tokens)
            return self.state_token_tokens(state_token)

    def fetch_state_token_tokens_no_expand(self):
        '''
        Fetch a single state token, in no-expand lex mode, and convert it into
        its terminal tokens.
        '''
        old_lex_mode = self.lex_mode
        self.lex_mode = LexMode.no_expand
        tokens = self.fetch_state_token_tokens()
        self.lex_mode = old_lex_mode
        return tokens

    def state_token_tokens_control_sequence(self, state_token):
        tokens = []
        name = state_token['name']
        if self.lex_mode == LexMode.no_expand:
            if len(name) == 1:
                type_ = 'SINGLE_CHAR_CONTROL_SEQUENCE'
            else:
                type_ = 'CONTROL_SEQUENCE'
            tokens.append(PLYToken(type_=type_, value=state_token))
        elif name in self.state.control_sequences:
            control_sequence_state_tokens = self.expand_control_sequence(name)
            for cs_state_token in control_sequence_state_tokens:
                cs_terminal_tokens = self.state_token_tokens(cs_state_token)
                tokens.extend(cs_terminal_tokens)
        elif name in primitive_control_sequences_map:
            token_type = primitive_control_sequences_map[name]
            tokens.append(PLYToken(type_=token_type, value=state_token))
            if name in read_control_sequence_name_tokens:
                next_tokens = self.fetch_state_token_tokens_no_expand()
                assert len(next_tokens) == 1
                tokens.extend(next_tokens)
        elif name in ('global', 'long', 'outer'):
            tokens.append(PLYToken(type_='PREFIX', value=state_token))
        else:
            import pdb; pdb.set_trace()
        return tokens

    def state_token_tokens_char(self, state_token):
        tokens = []
        char, cat = state_token['char'], state_token['cat']
        if cat in (CatCode.letter, CatCode.other):
            if (char, cat) in literals_map:
                type_ = literals_map[(char, cat)]
            else:
                type_ = 'CHARACTER'
        elif cat in category_map:
            type_ = category_map[cat]
        else:
            import pdb; pdb.set_trace()
        token = PLYToken(type_, value=state_token)
        tokens.append(token)
        # TODO: this will probably break when using backticks for
        # open-quotes.
        # Maybe move this to parse rule, at seen_BACKTICK?
        if type_ == 'BACKTICK':
            next_tokens = self.fetch_state_token_tokens_no_expand()
            assert len(next_tokens) == 1
            tokens.extend(next_tokens)
        return tokens

    def state_token_tokens(self, state_token):
        '''
        Converts a single state token into one or more terminal tokens.
        One important case where one state token produces many terminal tokens,
        is when the state token is a macro call, which is expanded into the
        stored state tokens.
        '''
        tokens = []
        if state_token['type'] == 'control_sequence':
            tokens = self.state_token_tokens_control_sequence(state_token)
        elif state_token['type'] == 'char_cat_pair':
            tokens = self.state_token_tokens_char(state_token)
        elif state_token['type'] in short_hand_def_token_map:
            type_ = short_hand_def_token_map[state_token['type']]
            token = PLYToken(type_=type_, value=state_token['value'])
            tokens.append(token)
        else:
            import pdb; pdb.set_trace()
        logger.info(tokens)
        return tokens

    def token(self):
        if not self.tokens_stack:
            try:
                tokens = self.fetch_state_token_tokens()
            except StopIteration:
                return
            self.tokens_stack.extend(tokens)
        token = self.tokens_stack.popleft()
        return token

class PLYToken(LexToken):

    def __init__(self, type_, value):
        self.type = type_
        self.value = value
        self.lineno = None
        self.lexpos = None

    def __repr__(self):
        return "<Token: %r %r>" % (self.type, self.value)

    def __str__(self):
        return self.__repr__()
<|endoftext|>


<commit_before>import ctypes as ct
import numpy as np
import os
import xdrlib
import operator as op
import sys

def write(path, v):
  path = os.path.expanduser(path)
  fid = open(path, 'wb')

  lines = []
  # write the ascii header
  lines.append('# AVS field file (written by avsfld.py)\n')
  ndim = len(v.shape)
  lines.append('ndim=%d\n' % ndim)
  for d in xrange(ndim):
    lines.append('dim%d=%d\n' % (d+1, v.shape[d]))
  lines.append('nspace=%d\n' % ndim)
  lines.append('veclen=1\n')

  if v.dtype == ct.c_float:
    lines.append('data=float_le\n')
  else:
    raise NotImplementedError('dtype %s not implemented' % str(v.dtype))
  lines.append('field=uniform\n')
  lines.append(chr(12))
  lines.append(chr(12))

  fid.writelines(lines)
  fid.write(v.swapaxes(0, ndim-1).tostring())
  fid.close()

def read(path):
  path = os.path.expanduser(path)
  fid = open(path, 'rb')

  # read the fld header
  ascii_header = []
  last_form_feed = False
  while True:
    next_char = fid.read(1)
    # end of ascii section
    if next_char == '' or (ord(next_char) == 12 and last_form_feed):
      break
    else:
      ascii_header.append(next_char)
    last_form_feed = ord(next_char) == 12
  header_lines = ("".join(ascii_header)).split("\n")

  # parse fld header
  header = {}
  def parse_line(line):
    split = line.split('=')
    return (split[0], " ".join(split[1:]))

  for k, v in [parse_line(line) for line in header_lines]:
    header[k] = v

  # get interesting info from header
  ndim = int(header['ndim'])
  dimnames = ["dim%d" % (n+1) for n in xrange(ndim)]
  shape = tuple([int(header[dimname]) for dimname in dimnames])

  if header['field'] != 'uniform':
    raise NotImplementedError('field %s not implemented' % header['field'])

  size = reduce(op.mul, shape)
  raw_data = None

  # external
  fname = None
  if 'variable 1 file' in header.keys():
    fid.close()
    p = os.path.dirname(path)
    if p != '': p = '%s/' % p
    fname = "%s%s" % (p,
        header['variable 1 file'].split(' ')[0])
    fid = open(fname, 'rb')

  if header['data'] == 'xdr_float':
    # slow path
    unpacker = xdrlib.Unpacker(fid.read())
    unpacked = unpacker.unpack_farray(size, unpacker.unpack_float)
    raw_data = np.asarray(unpacked, order='F', dtype=ct.c_float)
  elif header['data'] == 'float_le':
    if sys.byteorder != 'little':
      raise NotImplementedError('byte-swapping not implemented')
    raw_data = np.fromfile(fid, dtype=ct.c_float)
  else:
    raise NotImplementedError('datatype %s not implemented' % header['data'])

  fid.close()
  return raw_data.reshape(tuple(reversed(shape))).swapaxes(0,ndim-1)

<commit_msg>support for byte data type<commit_after>import ctypes as ct
import numpy as np
import os
import xdrlib
import operator as op
import sys

def write(path, v):
  path = os.path.expanduser(path)
  fid = open(path, 'wb')

  lines = []
  # write the ascii header
  lines.append('# AVS field file (written by avsfld.py)\n')
  ndim = len(v.shape)
  lines.append('ndim=%d\n' % ndim)
  for d in xrange(ndim):
    lines.append('dim%d=%d\n' % (d+1, v.shape[d]))
  lines.append('nspace=%d\n' % ndim)
  lines.append('veclen=1\n')

  if v.dtype == ct.c_float:
    lines.append('data=float_le\n')
  else:
    raise NotImplementedError('dtype %s not implemented' % str(v.dtype))
  lines.append('field=uniform\n')
  lines.append(chr(12))
  lines.append(chr(12))

  fid.writelines(lines)
  fid.write(v.swapaxes(0, ndim-1).tostring())
  fid.close()

def read(path):
  path = os.path.expanduser(path)
  fid = open(path, 'rb')

  # read the fld header
  ascii_header = []
  last_form_feed = False
  while True:
    next_char = fid.read(1)
    # end of ascii section
    if next_char == '' or (ord(next_char) == 12 and last_form_feed):
      break
    else:
      ascii_header.append(next_char)
    last_form_feed = ord(next_char) == 12
  header_lines = ("".join(ascii_header)).split("\n")

  # parse fld header
  header = {}
  def parse_line(line):
    split = line.split('=')
    return (split[0], " ".join(split[1:]))

  for k, v in [parse_line(line) for line in header_lines]:
    header[k] = v

  # get interesting info from header
  ndim = int(header['ndim'])
  dimnames = ["dim%d" % (n+1) for n in xrange(ndim)]
  shape = tuple([int(header[dimname]) for dimname in dimnames])

  if header['field'] != 'uniform':
    raise NotImplementedError('field %s not implemented' % header['field'])

  size = reduce(op.mul, shape)
  raw_data = None

  # external
  fname = None
  if 'variable 1 file' in header.keys():
    fid.close()
    p = os.path.dirname(path)
    if p != '': p = '%s/' % p
    fname = "%s%s" % (p,
        header['variable 1 file'].split(' ')[0])
    fid = open(fname, 'rb')

  if header['data'] == 'xdr_float':
    # slow path
    unpacker = xdrlib.Unpacker(fid.read())
    unpacked = unpacker.unpack_farray(size, unpacker.unpack_float)
    raw_data = np.asarray(unpacked, order='F', dtype=ct.c_float)
  elif header['data'] == 'float_le':
    if sys.byteorder != 'little':
      raise NotImplementedError('byte-swapping not implemented')
    raw_data = np.fromfile(fid, dtype=ct.c_float)
  elif header['data'] == 'byte':
    raw_data = np.fromfile(fid, dtype='uint8')
  else:
    raise NotImplementedError('datatype %s not implemented' % header['data'])

  fid.close()
  return raw_data.reshape(tuple(reversed(shape))).swapaxes(0,ndim-1)

<|endoftext|>


<commit_before>import os, sys
import getopt
from app.configparser import config
from app.app import run_instance
from app.models.init_models import init_models
import multiprocessing

devserver = config('DEVSERVER')
prserver = config('PRODUCTION_SERVER')

def error_handler(fn):
	pass

def devserver(port=devserver['PORT'], host=devserver['HOST']):
	run_instance(port, host)

def server(instances=prserver['INSTANCES']):
	port = prserver['MAIN_PORT']
	host = prserver['HOST']
	for ins in range(prserver['INSTANCES']):
		process = multiprocessing.Process(target=run_instance, args=(port + ins, host))
		process.start()

def dbsync():
	try:
		print('Models syncronization...')
		init_models()
	except Exception as e:
		print(e)

if __name__ == '__main__':
	try:
		action = sys.argv[1]
		# opts = sys.argv[2:]
		# if len(opts) > 0:
		# 	try:
		# 		opts, args = getopt.getopt(sys.argv[2:], "p", ["help", "output="])
		# 	except Exception as e:
		# 		raise Exception("Unknown option key")
		# print(opts)

	except IndexError:
		raise Exception("Missed required argument")

	actions = {
		'run':{
			'fn': server,
			'kwrgs': {},
			'options': []
		},
		'dev-server': {
			'fn': devserver,
			'kwrgs': {},
			'options': []
		},
		'dbsync': {
			'fn': dbsync,
			'kwrgs': {},
			'options': []
		},
	}

	if action not in actions:
		raise Exception("Invalid option")

	ac = actions[action]
	ac['fn'](**ac['kwrgs'])
<commit_msg>Replaced DEVSERVER to DEV_SERVER<commit_after>import os, sys
import getopt
from app.configparser import config
from app.app import run_instance
from app.models.init_models import init_models
import multiprocessing

devserver = config('DEV_SERVER')
prserver = config('PRODUCTION_SERVER')

def error_handler(fn):
	pass

def devserver(port=devserver['PORT'], host=devserver['HOST']):
	run_instance(port, host)

def server(instances=prserver['INSTANCES']):
	port = prserver['MAIN_PORT']
	host = prserver['HOST']
	for ins in range(prserver['INSTANCES']):
		process = multiprocessing.Process(target=run_instance, args=(port + ins, host))
		process.start()

def dbsync():
	try:
		print('Models syncronization...')
		init_models()
	except Exception as e:
		print(e)

if __name__ == '__main__':
	try:
		action = sys.argv[1]
		# opts = sys.argv[2:]
		# if len(opts) > 0:
		# 	try:
		# 		opts, args = getopt.getopt(sys.argv[2:], "p", ["help", "output="])
		# 	except Exception as e:
		# 		raise Exception("Unknown option key")
		# print(opts)

	except IndexError:
		raise Exception("Missed required argument")

	actions = {
		'run':{
			'fn': server,
			'kwrgs': {},
			'options': []
		},
		'dev-server': {
			'fn': devserver,
			'kwrgs': {},
			'options': []
		},
		'dbsync': {
			'fn': dbsync,
			'kwrgs': {},
			'options': []
		},
	}

	if action not in actions:
		raise Exception("Invalid option")

	ac = actions[action]
	ac['fn'](**ac['kwrgs'])
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# Robot Framework documentation build configuration file, created by
# sphinx-quickstart on Sun Oct 23 11:12:31 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(os.path.join('.', '..', '..', 'src')))

from robot.version import VERSION, get_version

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
autoclass_content = "both"
autodoc_member_order = "bysource"
autodoc_default_flags = ["inherited-members"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'Robot Framework'
copyright = u'2013, Nokia Siemens Networks'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = VERSION
# The full version, including alpha/beta/rc tags.
release = get_version()

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'RobotFrameworkdoc'

# -- Options for LaTeX output --------------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'RobotFramework.tex', u'Robot Framework Documentation',
   u'Robot Framework developers', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'robotframework', u'Robot Framework Documentation',
     [u'Robot Framework developers'], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False

# -- Options for Texinfo output ------------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'RobotFramework', u'Robot Framework Documentation', u'Robot Framework developers',
   'RobotFramework', 'One line description of project.', 'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

def non_example_lines(line):
    if not line.startswith(('| ', 'Examples', 'Example', '=>')):
        return True

def remove_library_examples(app, what, name, obj, options, lines):
    if name.startswith("robot.libraries"):
        lines[:] = filter(non_example_lines, lines)

def setup(app):
    app.connect('autodoc-process-docstring', remove_library_examples)
<commit_msg>Automated merge with https://code.google.com/p/robotframework/<commit_after># -*- coding: utf-8 -*-
#
# Robot Framework documentation build configuration file, created by
# sphinx-quickstart on Sun Oct 23 11:12:31 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(os.path.join('.', '..', '..', 'src')))

from robot.version import VERSION, get_version

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
autoclass_content = 'both'
autodoc_default_flags = ['members', 'undoc-members', 'inherited-members']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'Robot Framework'
copyright = u'2013, Nokia Siemens Networks'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = VERSION
# The full version, including alpha/beta/rc tags.
release = get_version()

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'RobotFrameworkdoc'

# -- Options for LaTeX output --------------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'RobotFramework.tex', u'Robot Framework Documentation',
   u'Robot Framework developers', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'robotframework', u'Robot Framework Documentation',
     [u'Robot Framework developers'], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False

# -- Options for Texinfo output ------------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'RobotFramework', u'Robot Framework Documentation', u'Robot Framework developers',
   'RobotFramework', 'One line description of project.', 'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

def non_example_lines(line):
    if not line.startswith(('| ', 'Examples', 'Example', '=>')):
        return True

def remove_library_examples(app, what, name, obj, options, lines):
    if name.startswith("robot.libraries"):
        lines[:] = filter(non_example_lines, lines)

def setup(app):
    app.connect('autodoc-process-docstring', remove_library_examples)
<|endoftext|>


<commit_before>import re
from babbisch.odict import odict
from .names import oocize_name
from .wraplib.ooc import INDENT, DEDENT, Function, Class, Method

import yaml

def _match_by_name(loader, node):
    """
        This can be followed by a mapping or a string (as a short-hand).
    """
    if isinstance(node, yaml.nodes.MappingNode):
        options = loader.construct_mapping(node)
        regex = re.compile(options['regex'])
        this_idx = int(options.get('this_idx', 0))
    else:
        regex = re.compile(loader.construct_scalar(node))
        this_idx = 0
    def matches(client, obj):
        match = regex.match(obj['name'])
        if match is not None:
            return (match.group(1), this_idx)
        else:
            return False
    return matches

def _match_by_tag(loader, node):
    """
        Mapping or string, baby.
    """
    if isinstance(node, yaml.nodes.MappingNode):
        options = loader.construct_mapping(node)
        tag = options['tag']
        this_idx = int(options.get('this_idx', 0))
        name_regex = re.compile(options['name_regex'])
    else:
        tag = loader.construct_scalar(node)
        this_idx = 0
        name_regex = re.compile('.*')
    def matches(client, obj):
        if len(obj['arguments']) <= this_idx:
            return False
        elif obj['arguments'][this_idx][1] == tag:
            return (name_regex.match(obj['name']).group(1), this_idx)
        else:
            return False
    return matches

yaml.add_constructor(u'!by_name', _match_by_name)
yaml.add_constructor(u'!by_tag', _match_by_tag)

def _apply_methods(client, object_name, object_info):
    for obj in client.objects.itervalues():
        if obj['class'] == 'Function':
            wrapped = False
            # Static methods!
            for matcher in object_info.get('static_methods', ()):
                result = matcher(client, obj)
                if result:
                    method_name, this_idx = result
                    # Add the method. We're just implicitly occizing the name. Evil, isn't it?
                    client.add_method(obj['name'], oocize_name(method_name), object_name, static=True)
                    wrapped = True
                    break
            # Methods!
            if not wrapped:
                for matcher in object_info.get('methods', ()):
                    result = matcher(client, obj)
                    if result:
                        method_name, this_idx = result
                        # Add the method. We're just implicitly occizing the name. Evil, isn't it?
                        client.add_method(obj['name'], oocize_name(method_name), object_name, this_idx)

def _apply_properties(client, object_name, object_info):
    for name, prop_info in object_info.get('properties', {}).iteritems():
        client.add_property(
            object_name,
            name,
            prop_info['type'],
            prop_info.get('getter'),
            prop_info.get('setter'),
            prop_info.get('static', False)
        )

def apply_settings(client):
    """
        Apply all oo settings.
    """
    # Add artificial covers.
    for object_name, info in client.interface.get('Objects', {}).iteritems():
        client.add_artificial_cover(object_name, info['type'], info['tag'], info.get('extends', ''))
        # Add methods.
        _apply_methods(client, object_name, info)
        # Properties.
        _apply_properties(client, object_name, info)
    apply_errors(client)

def apply_errors(client):
    if 'Errors' in client.interface:
        # add check func / exeption
        cls = make_check_exception()
        client._codegens[cls.name] = cls
        func = make_check_func(client.interface['Errors'].get('names', []))
        client._codegens[func.name] = func
        # mark checked functions
        matchers = client.interface['Errors'].get('functions', [])
        for obj in client.objects.itervalues():
            if obj['class'] == 'Function':
                for matcher in matchers:
                    result = matcher(client, obj)
                    if result:
                        client.checked_functions.append(obj['name'])

ERROR_CHECKING_FUNCTION = '_checkError'

def make_check_func(errors):
    func = Function(ERROR_CHECKING_FUNCTION, args=odict([('code', 'Int')]), rettype='Int')
    func.code.extend([
        'if(code != 0) {', INDENT,
            'Failure new(match(code) {', INDENT
    ])
    for error in errors:
        func.code.append('case %s => "%s"' % (error, error))
    func.code.extend(['case => code toString()', DEDENT, '}) throw()', DEDENT, '}',
                      'return code'])
    return func

def make_check_exception():
    cls = Class('Failure', 'Exception')
    init = Method('init~withCode', args=odict([('code', 'String')]))
#    init.code.append('super(code)')
    cls.add_member(init)
    return cls

def errorize_function(client, name, wrapper, checking_func=ERROR_CHECKING_FUNCTION):
    """
        Make the function *wrapper* wrap all errors.
    """
    assert not wrapper.code
    wrapper.code = [
            'return %s(%s(%s))' % (checking_func, name, ', '.join(wrapper.arguments.iterkeys())),
    ]
    client.generate_function(client.objects[name], True)
<commit_msg>Fixed error handling.<commit_after>import re
from babbisch.odict import odict
from .names import oocize_name
from .wraplib.ooc import INDENT, DEDENT, Function, Class, Method

import yaml

def _match_by_name(loader, node):
    """
        This can be followed by a mapping or a string (as a short-hand).
    """
    if isinstance(node, yaml.nodes.MappingNode):
        options = loader.construct_mapping(node)
        regex = re.compile(options['regex'])
        this_idx = int(options.get('this_idx', 0))
    else:
        regex = re.compile(loader.construct_scalar(node))
        this_idx = 0
    def matches(client, obj):
        match = regex.match(obj['name'])
        if match is not None:
            return (match.group(1), this_idx)
        else:
            return False
    return matches

def _match_by_tag(loader, node):
    """
        Mapping or string, baby.
    """
    if isinstance(node, yaml.nodes.MappingNode):
        options = loader.construct_mapping(node)
        tag = options['tag']
        this_idx = int(options.get('this_idx', 0))
        name_regex = re.compile(options['name_regex'])
    else:
        tag = loader.construct_scalar(node)
        this_idx = 0
        name_regex = re.compile('.*')
    def matches(client, obj):
        if len(obj['arguments']) <= this_idx:
            return False
        elif obj['arguments'][this_idx][1] == tag:
            return (name_regex.match(obj['name']).group(1), this_idx)
        else:
            return False
    return matches

yaml.add_constructor(u'!by_name', _match_by_name)
yaml.add_constructor(u'!by_tag', _match_by_tag)

def _apply_methods(client, object_name, object_info):
    for obj in client.objects.itervalues():
        if obj['class'] == 'Function':
            wrapped = False
            # Static methods!
            for matcher in object_info.get('static_methods', ()):
                result = matcher(client, obj)
                if result:
                    method_name, this_idx = result
                    # Add the method. We're just implicitly occizing the name. Evil, isn't it?
                    client.add_method(obj['name'], oocize_name(method_name), object_name, static=True)
                    wrapped = True
                    break
            # Methods!
            if not wrapped:
                for matcher in object_info.get('methods', ()):
                    result = matcher(client, obj)
                    if result:
                        method_name, this_idx = result
                        # Add the method. We're just implicitly occizing the name. Evil, isn't it?
                        client.add_method(obj['name'], oocize_name(method_name), object_name, this_idx)

def _apply_properties(client, object_name, object_info):
    for name, prop_info in object_info.get('properties', {}).iteritems():
        client.add_property(
            object_name,
            name,
            prop_info['type'],
            prop_info.get('getter'),
            prop_info.get('setter'),
            prop_info.get('static', False)
        )

def apply_settings(client):
    """
        Apply all oo settings.
    """
    # Add artificial covers.
    for object_name, info in client.interface.get('Objects', {}).iteritems():
        client.add_artificial_cover(object_name, info['type'], info['tag'], info.get('extends', ''))
        # Add methods.
        _apply_methods(client, object_name, info)
        # Properties.
        _apply_properties(client, object_name, info)
    apply_errors(client)

def apply_errors(client):
    if 'Errors' in client.interface:
        # add check func / exeption
        cls = make_check_exception()
        client._codegens[cls.name] = cls
        func = make_check_func(client.interface['Errors'].get('names', []))
        client._codegens[func.name] = func
        # mark checked functions
        matchers = client.interface['Errors'].get('functions', [])
        for obj in client.objects.itervalues():
            if obj['class'] == 'Function':
                for matcher in matchers:
                    result = matcher(client, obj)
                    if result:
                        client.checked_functions.append(obj['name'])

ERROR_CHECKING_FUNCTION = '_checkError'

def make_check_func(errors):
    func = Function(ERROR_CHECKING_FUNCTION, args=odict([('code', 'Int')]), rettype='Int')
    func.code.extend([
        'if(code != 0) {', INDENT,
            'Failure new(match(code) {', INDENT
    ])
    for error in errors:
        func.code.append('case %s => "%s"' % (error, error))
    func.code.extend(['case => code toString()', DEDENT, '}) throw()', DEDENT, '}',
                      'return code'])
    return func

def make_check_exception():
    cls = Class('Failure', 'Exception')
    init = Method('init~withCode', args=odict([('code', 'String')]))
    init.code.append('super(code)')
    cls.add_member(init)
    return cls

def errorize_function(client, name, wrapper, checking_func=ERROR_CHECKING_FUNCTION):
    """
        Make the function *wrapper* wrap all errors.
    """
    assert not wrapper.code
    wrapper.code = [
            'return %s(%s(%s))' % (checking_func, name, ', '.join(wrapper.arguments.iterkeys())),
    ]
    for mod in wrapper.modifiers[:]:
        if mod.startswith('extern'):
            wrapper.modifiers.remove(mod)
    client.generate_function(client.objects[name], True)
<|endoftext|>


<commit_before>import logging
from ipaddress import IPv4Address, AddressValueError

from flask import current_app
from sqlalchemy import create_engine
from sqlalchemy.exc import OperationalError

from sipa.model.user import BaseUserDB
from sipa.backends.exceptions import InvalidConfiguration

logger = logging.getLogger(__name__)

class UserDB(BaseUserDB):
    def __init__(self, user):
        super().__init__(user)

        mask = current_app.config.get('DB_HELIOS_IP_MASK')
        self.test_ipmask_validity(mask)
        self.ip_mask = mask

    @staticmethod
    def test_ipmask_validity(mask):
        """Test whether a valid ip mask (at max one consecutive '%') was given

        This is being done by replacing '%' with the maximum possible
        value ('255').  Thus, everything surrounding the '%' except
        for dots causes an invalid IPv4Address and thus a
        `ValueError`.
        """
        try:
            IPv4Address(mask.replace("%", "255"))
        except AddressValueError:
            raise ValueError("Mask {} is not a valid IP address or contains "
                             "more than one consecutive '%' sign".format(mask))

    @staticmethod
    def sql_query(query, args=()):
        """Prepare and execute a raw sql query.
        'args' is a tuple needed for string replacement.
        """
        database = current_app.extensions['db_helios']
        # Connection.__enter__ returns Cursor, Cursor.__enter__ returns itself
        # and we need both things for their `__exit__` commands
        with database.connect() as cursor, cursor:
            result = cursor.execute(query, args)
        return result

    @property
    def has_db(self):
        try:
            userdb = self.sql_query(
                "SELECT SCHEMA_NAME "
                "FROM INFORMATION_SCHEMA.SCHEMATA "
                "WHERE SCHEMA_NAME = %s",
                (self.db_name(),),
            ).fetchone()

            return userdb is not None
        except OperationalError:
            logger.critical("User db of user %s unreachable", self.db_name(),
                            exc_info=True)
            return None

    def create(self, password):
        self.sql_query(
            "CREATE DATABASE "
            "IF NOT EXISTS `%s`" % self.db_name(),
        )
        self.change_password(password)

    def drop(self):
        self.sql_query(
            "DROP DATABASE "
            "IF EXISTS `%s`" % self.db_name(),
        )

        self.sql_query(
            "DROP USER %s@%s",
            (self.db_name(), self.ip_mask),
        )

    def change_password(self, password):
        user = self.sql_query(
            "SELECT user "
            "FROM mysql.user "
            "WHERE user = %s",
            (self.db_name(),),
        ).fetchall()

        if not user:
            self.sql_query(
                "CREATE USER %s@%s "
                "IDENTIFIED BY %s",
                (self.db_name(), self.ip_mask, password,),
            )
        else:
            self.sql_query(
                "SET PASSWORD "
                "FOR %s@%s = PASSWORD(%s)",
                (self.db_name(), self.ip_mask, password,),
            )

        self.sql_query(
            "GRANT SELECT, INSERT, UPDATE, DELETE, "
            "ALTER, CREATE, DROP, INDEX, LOCK TABLES "
            "ON `{}`.* "
            "TO %s@%s".format(self.db_name()),
            (self.db_name(), self.ip_mask),
        )

    def db_name(self):
        return self.user.login.value

def register_userdb_extension(app):
    try:
        app.extensions['db_helios'] = create_engine(
            app.config['DB_HELIOS_URI'],
            echo=False, connect_args={'connect_timeout': app.config['SQL_TIMEOUT']}
        )
    except KeyError as exception:
        raise InvalidConfiguration(*exception.args)
<commit_msg>Improve `sql_query` method documentation<commit_after>import logging
from ipaddress import IPv4Address, AddressValueError

from flask import current_app
from sqlalchemy import create_engine
from sqlalchemy.exc import OperationalError

from sipa.model.user import BaseUserDB
from sipa.backends.exceptions import InvalidConfiguration

logger = logging.getLogger(__name__)

class UserDB(BaseUserDB):
    def __init__(self, user):
        super().__init__(user)

        mask = current_app.config.get('DB_HELIOS_IP_MASK')
        self.test_ipmask_validity(mask)
        self.ip_mask = mask

    @staticmethod
    def test_ipmask_validity(mask):
        """Test whether a valid ip mask (at max one consecutive '%') was given

        This is being done by replacing '%' with the maximum possible
        value ('255').  Thus, everything surrounding the '%' except
        for dots causes an invalid IPv4Address and thus a
        `ValueError`.
        """
        try:
            IPv4Address(mask.replace("%", "255"))
        except AddressValueError:
            raise ValueError("Mask {} is not a valid IP address or contains "
                             "more than one consecutive '%' sign".format(mask))

    @staticmethod
    def sql_query(query: str, args=()):
        """Prepare and execute a raw sql query.

        :param query: See :py:meth:`pymysql.cursors.Cursor.execute`.
        :param args: is a tuple needed for string replacement.
            See :py:meth:`pymysql.cursors.Cursor.execute`.
        """
        database = current_app.extensions['db_helios']
        # Connection.__enter__ returns Cursor, Cursor.__enter__ returns itself
        # and we need both things for their `__exit__` commands
        with database.connect() as cursor, cursor:
            result = cursor.execute(query, args)
        return result

    @property
    def has_db(self):
        try:
            userdb = self.sql_query(
                "SELECT SCHEMA_NAME "
                "FROM INFORMATION_SCHEMA.SCHEMATA "
                "WHERE SCHEMA_NAME = %s",
                (self.db_name(),),
            ).fetchone()

            return userdb is not None
        except OperationalError:
            logger.critical("User db of user %s unreachable", self.db_name(),
                            exc_info=True)
            return None

    def create(self, password):
        self.sql_query(
            "CREATE DATABASE "
            "IF NOT EXISTS `%s`" % self.db_name(),
        )
        self.change_password(password)

    def drop(self):
        self.sql_query(
            "DROP DATABASE "
            "IF EXISTS `%s`" % self.db_name(),
        )

        self.sql_query(
            "DROP USER %s@%s",
            (self.db_name(), self.ip_mask),
        )

    def change_password(self, password):
        user = self.sql_query(
            "SELECT user "
            "FROM mysql.user "
            "WHERE user = %s",
            (self.db_name(),),
        ).fetchall()

        if not user:
            self.sql_query(
                "CREATE USER %s@%s "
                "IDENTIFIED BY %s",
                (self.db_name(), self.ip_mask, password,),
            )
        else:
            self.sql_query(
                "SET PASSWORD "
                "FOR %s@%s = PASSWORD(%s)",
                (self.db_name(), self.ip_mask, password,),
            )

        self.sql_query(
            "GRANT SELECT, INSERT, UPDATE, DELETE, "
            "ALTER, CREATE, DROP, INDEX, LOCK TABLES "
            "ON `{}`.* "
            "TO %s@%s".format(self.db_name()),
            (self.db_name(), self.ip_mask),
        )

    def db_name(self):
        return self.user.login.value

def register_userdb_extension(app):
    try:
        app.extensions['db_helios'] = create_engine(
            app.config['DB_HELIOS_URI'],
            echo=False, connect_args={'connect_timeout': app.config['SQL_TIMEOUT']}
        )
    except KeyError as exception:
        raise InvalidConfiguration(*exception.args)
<|endoftext|>