<commit_before>'''
Created on 21.10.2013

@author: northernstars
'''
from gui.GuiLoader import GuiLoader
from core.ImageGrabber import ImageGrabber
from core.imageprocessing import findChessBoardPatternSize, imageToPixmap, getChessBoardCorners
from core.imageprocessing import getCalibrationData, undistortImg, getImageSizeFromCorners

from numpy import float32, zeros, indices, prod
from cv2 import drawChessboardCorners, cvtColor, COLOR_BGR2RGB

from PyQt4.QtGui import QGraphicsScene
from PyQt4.QtCore import QTimer, Qt
from thread import start_new_thread
from copy import copy
from cPickle import dump, load

class Distortion(object):
    '''
    classdocs
    '''
    __gui = GuiLoader()
    __imageGrabber = ImageGrabber()

    __img = None
    __imgScene = None
    __imgCounter = 0

    __scene = None
    __gview = None
    __sceneImgTimer = None

    __camera_matrix = None
    __dist_coefs = None
    __corners = None

    __calibrated = False
    __calibrating = False

    def __init__(self, gui=None, imageGrabber=None):
        '''
        Constructor
        '''
        self.__gui = GuiLoader()
        self.__imageGrabber = ImageGrabber()
        self.__calibrated = False
        self.__calibrating = False

        if gui != None:
            self.__gui = gui
            self.__initGui()

        if imageGrabber != None:
            self.__imageGrabber = imageGrabber

    def __initGui(self):
        '''
        Initiates gui
        '''
        # initiate scene
        self.__gview = self.__gui.getObj("imgDistortion")
        self.__scene = QGraphicsScene()
        self.__gview.setScene(self.__scene)

        # create listeners
        self.__gui.connect( "cmdFindPattern", "clicked()", self.findChessBoardPattern )
        self.__gui.connect( "cmdCalibrateDistortion", "clicked()", self.calibrateCamera )
        self.__gui.connect( "cmdSaveDistortion", "clicked()", self.__saveConfiguration )
        self.__gui.connect( "cmdLoadDistortion", "clicked()", self.__loadConfiguration )
        self.__gui.connect( "chkCropImg", "toggled(bool)", self.__borderSelectionChanged )
        self.__gui.connect( "chkCropImgManual", "toggled(bool)", self.__borderSelectionChanged )

        # start timer
        self.__sceneImgTimer = QTimer()
        self.__sceneImgTimer.timeout.connect( self.__showImage )
        self.__sceneImgTimer.start(200)

    def isCalibrated(self):
        '''
        @return: True if image is calibrated
        '''
        return self.__calibrated

    def isCalibrating(self):
        '''
        @return: True if calibration is in progress
        '''
        return self.__calibrating

    def setImg(self, img=None):
        '''
        Sets current image
        '''
        self.__img = img
        self.__imgCounter += 1

    def __borderSelectionChanged(self):
        '''
        Checks selection of manual/auto
        border settings gui group
        '''
        if self.__gui.getObj("chkCropImgManual").isChecked():
            self.__gui.getObj("chkCropImg").setChecked(False)
            self.__gui.getObj("chkCropImg").setEnabled(False)
        else:
            self.__gui.getObj("chkCropImg").setEnabled(True)

        if self.__gui.getObj("chkCropImg").isChecked():
            self.__gui.getObj("chkCropImgManual").setChecked(False)
            self.__gui.getObj("chkCropImgManual").setEnabled(False)
        else:
            self.__gui.getObj("chkCropImgManual").setEnabled(True)

    def findChessBoardPattern(self):
        '''
        Finds maximum chessboard pattern
        '''
        # show message
        self.__imgScene = None
        self.__scene.clear()
        self.__scene.addSimpleText("Searching pattern...\nThis will take a while")
        self.__gview.show()

        # start search
        start_new_thread( self.__searchChessBoardPattern, () )

    def __searchChessBoardPattern(self):
        '''
        Searches for chessboard pattern
        (start in background)
        '''

        # get start and max values
        xStart = int( str( self.__gui.getObj("txtPatternXMin").text() ) )
        yStart =  int( str( self.__gui.getObj("txtPatternYMin").text() ) )
        xMax =  int( str( self.__gui.getObj("txtPatternXMax").text() ) )
        yMax =  int( str( self.__gui.getObj("txtPatternYMax").text() ) )

        # find pattern
        if self.__img != None:
            pattern = findChessBoardPatternSize(self.__img, xMax, yMax, xStart, yStart)

            if pattern != None and len(pattern) > 0:
                # set pattern
                if len(pattern) == 2:
                    self.__gui.getObj("txtPatternX").setText( str(pattern[0]) )
                    self.__gui.getObj("txtPatternY").setText( str(pattern[1]) )

    def calibrateCamera(self):
        '''
        Calibrates camera
        '''
        start_new_thread(self.__calibrate, ())

    def __calibrate(self):
        '''
        Calibrates camera
        (run in background)
        '''
        # check for correct image
        if self.__img != None:
            self.__calibrating = True
            self.__gui.status("Calibrating ...")

            # get values
            x = int(str( self.__gui.getObj("txtPatternX").text() ))
            y = int(str( self.__gui.getObj("txtPatternY").text() ))
            n = int(str( self.__gui.getObj("txtCalibrationFrames").text() ))
            square_size = float(str( self.__gui.getObj("txtCalibrationSquareSize").text() ))

            # calculate distortion
            pattern_size = (x, y)
            ret = self.__calibrateCorners(pattern_size, n, square_size)

            if ret != None:
                camera_matrix, dist_coefs = ret
                self.__camera_matrix, self.__dist_coefs = camera_matrix, dist_coefs

            # undistort image
            img = self.undistortImage(self.__img)
            self.__imgScene = img

            self.__gui.status("Searching for boders to crop image ...")

            # get corners
            if ret != None:
                found = False
                frames = 0;
                tries = 0;
                while not found and frames < n and tries < 10:
                    img = self.undistortImage(self.__img)
                    found, corners = getChessBoardCorners( img, pattern_size )
                    if found:
                        frames += 1
                    tries += 1

                if found:
                    self.__corners = getImageSizeFromCorners(corners)

            # crop image
            self.__imgScene = self.cropImage(img)
            self.__calibrated = True

        # set calibration flag
        self.__gui.status("Calibration finished.")

        self.__calibrating = False

    def __calibrateCorners(self, pattern_size, n, square_size):
        '''
        Calibrates corners of chessboard
        @return: camera_matrix, dist_coefs
        '''
        pattern_points = zeros( (prod(pattern_size), 3), float32 )
        pattern_points[:,:2] = indices(pattern_size).T.reshape(-1, 2)
        pattern_points *= square_size

        obj_points = []
        img_points = []
        frames = 0;
        tries = 0
        lastCount = self.__imgCounter;

        # detect pattern
        while frames < n and tries < 10:
            img = self.__img

            if lastCount != self.__imgCounter:
                # get corners
                found, corners = getChessBoardCorners( img, pattern_size )

                # check if corners found
                if found:
                    frames += 1

                    # get more detailed points and add them to list
                    img_points.append( corners.reshape(-1, 2) )
                    obj_points.append( pattern_points )

                    # draw corners
                    drawChessboardCorners( img, pattern_size, corners, found )
                    self.__imgScene = img
                    tries = 0
                tries += 1

        # get cmera values
        if img != None and len(obj_points) > 0 and len(img_points) > 0:
            return getCalibrationData(img, obj_points, img_points )

    def cropImage(self, img=None):
        '''
        Crops image if corners available
        @return: croped Image
        '''

        if self.__corners != None and img != None and ( self.__gui.getObj("chkCropImg").isChecked() or self.__gui.getObj("chkCropImgManual").isChecked() ) :

            # default settings for manual crop
            borderX = int( str(self.__gui.getObj("txtBorderLR").text()) )
            borderY = int( str(self.__gui.getObj("txtBorderTB").text()) )

            xmin = (img.shape[1]-1)/2 - borderX
            xmax = (img.shape[1]-1)/2 + borderX
            ymin = (img.shape[0]-1)/2 - borderY
            ymax = (img.shape[0]-1)/2 + borderY

            # settings for automatic crop
            if self.__gui.getObj("chkCropImg").isChecked():
                borders = int(str( self.__gui.getObj("txtCalibrationBorders").text() )) / 100.0
                borderX = int(img.shape[1] * borders)
                borderY = int(img.shape[0] * borders)

                xmin = int(self.__corners[0][0])
                xmax = int(self.__corners[0][1])
                ymin = int(self.__corners[1][0])
                ymax = int(self.__corners[1][1])

            # check new borders
            if xmin-borderX > 0:
                xmin = xmin-borderX
            else:
                xmin = 0

            if ymin-borderY > 0:
                ymin = ymin-borderY
            else:
                ymin = 0

            if xmax+borderX <= img.shape[1]:
                xmax = xmax+borderX
            else:
                xmax = img.shape[1]-1

            if ymax+borderY <= img.shape[0]:
                ymax = ymax+borderY
            else:
                ymax = img.shape[0]-1

            # conversion before
            if self.__gui.getObj("chkCropConvBefore").isChecked():
                img = cvtColor( img, COLOR_BGR2RGB )

            # crop image
            try:
                img = img[ymin:ymax, xmin:xmax]

                # conversion after
                img = cvtColor( img, COLOR_BGR2RGB )
            except:
                print "ERROR"

        return img

    def __showImage(self):
        '''
        Shows image
        '''
        if self.__imgScene != None:
            self.__scene.clear()
            self.__scene.addPixmap( imageToPixmap(self.__imgScene) )
            self.__gview.fitInView( self.__scene.sceneRect(), Qt.KeepAspectRatio )
            self.__gview.show()

    def undistortImage(self, img=None):
        '''
        Undistorts image
        @return: Image
        '''
        if self.__camera_matrix != None and self.__dist_coefs != None and img != None:
            return undistortImg( img, self.__camera_matrix, self.__dist_coefs )
        return img

    def __loadConfiguration(self):
        '''
        Loads configuration
        '''
        # stop video
        active = self.__imageGrabber.isActive()
        self.__imageGrabber.stopVideo()

        # get path
        options = copy(self.__gui.dialogOptionsDef)
        options['filetypes'] = "config file (*cfg)"
        src = str( self.__gui.dialog(options) )

        if len(src) > 0:
            # load file
            data = load( open(src, "rb") )

            if 'camera_matrix' in data:
                self.__camera_matrix = data['camera_matrix']
            if 'dist_coefs' in data:
                self.__dist_coefs = data['dist_coefs']
            if 'corners' in data:
                self.__corners = data['corners']
            if 'calibrated' in data:
                self.__calibrated = data['calibrated']
            if 'cropmanual' in data:
                self.__gui.getObj("chkCropImgManual").setChecked( data['cropmanual'] )
            if 'cropauto' in data:
                self.__gui.getObj("chkCropImg").setChecked( data['cropauto'] )
            if 'cropBorderLR' in data:
                self.__gui.getObj("txtBorderLR").setText( data['cropBorderLR'] )
            if 'cropBorderTB' in data:
                self.__gui.getObj("txtBorderTB").setText( data['cropBorderTB'] )
            if 'cropauto' in data:
                self.__gui.getObj("txtCalibrationBorders").setText( data['cropauto'] )
            if 'squareSize' in data:
                self.__gui.getObj("txtCalibrationSquareSize").setText( data['squareSize'] )
            if 'calibFrames' in data:
                self.__gui.getObj("txtCalibrationFrames").setText( data['calibFrames'] )
            if 'patternX' in data:
                self.__gui.getObj("txtPatternX").setText( data['patternX'] )
            if 'patternY' in data:
                self.__gui.getObj("txtPatternY").setText( data['patternY'] )

            self.__gui.status("Configuration loaded.")

        # restore video streaming mode
        if active:
            self.__imageGrabber.startVideo()

    def __saveConfiguration(self):
        '''
        Saves configuration
        '''
        # stop video
        active = self.__imageGrabber.isActive()
        self.__imageGrabber.stopVideo()

        options = copy(self.__gui.dialogOptionsDef)
        options['type'] = self.__gui.dialogTypes['FileSave']
        options['title'] = "Save configuration"
        options['filetypes'] = "Configuration (*cfg *mr)"
        src = str( self.__gui.dialog(options) )

        if len(src) > 0:
            # check path
            if not src.endswith(".cfg"):
                src += ".cfg"

            # save data to file
            data = {'camera_matrix': self.__camera_matrix,
                    'dist_coefs': self.__dist_coefs,
                    'corners': self.__corners,
                    'calibrated': self.__calibrated,
                    'cropmanual': self.__gui.getObj("chkCropImgManual").isChecked(),
                    'cropauto:': self.__gui.getObj("chkCropImg").isChecked(),
                    'cropBorder': str( self.__gui.getObj("txtCalibrationBorders").text() ),
                    'cropBorderLR': str( self.__gui.getObj("txtBorderLR").text() ),
                    'cropBorderTB': str( self.__gui.getObj("txtBorderTB").text() ),
                    'squareSize': str( self.__gui.getObj("txtCalibrationSquareSize").text() ),
                    'calibFrames': str( self.__gui.getObj("txtCalibrationFrames").text() ),
                    'patternX': str( self.__gui.getObj("txtPatternX").text() ),
                    'patternY': str( self.__gui.getObj("txtPatternY").text() )}

            dump( data, open(src, "wb") )
            self.__gui.status("Configuration saved to: " + src)

        # restore video streaming mode
        if active:
            self.__imageGrabber.startVideo()<commit_msg>Updated automatic border crop to accept dezimal percent values.<commit_after>'''
Created on 21.10.2013

@author: northernstars
'''
from gui.GuiLoader import GuiLoader
from core.ImageGrabber import ImageGrabber
from core.imageprocessing import findChessBoardPatternSize, imageToPixmap, getChessBoardCorners
from core.imageprocessing import getCalibrationData, undistortImg, getImageSizeFromCorners

from numpy import float32, zeros, indices, prod
from cv2 import drawChessboardCorners, cvtColor, COLOR_BGR2RGB

from PyQt4.QtGui import QGraphicsScene
from PyQt4.QtCore import QTimer, Qt
from thread import start_new_thread
from copy import copy
from cPickle import dump, load

class Distortion(object):
    '''
    classdocs
    '''
    __gui = GuiLoader()
    __imageGrabber = ImageGrabber()

    __img = None
    __imgScene = None
    __imgCounter = 0

    __scene = None
    __gview = None
    __sceneImgTimer = None

    __camera_matrix = None
    __dist_coefs = None
    __corners = None

    __calibrated = False
    __calibrating = False

    def __init__(self, gui=None, imageGrabber=None):
        '''
        Constructor
        '''
        self.__gui = GuiLoader()
        self.__imageGrabber = ImageGrabber()
        self.__calibrated = False
        self.__calibrating = False

        if gui != None:
            self.__gui = gui
            self.__initGui()

        if imageGrabber != None:
            self.__imageGrabber = imageGrabber

    def __initGui(self):
        '''
        Initiates gui
        '''
        # initiate scene
        self.__gview = self.__gui.getObj("imgDistortion")
        self.__scene = QGraphicsScene()
        self.__gview.setScene(self.__scene)

        # create listeners
        self.__gui.connect( "cmdFindPattern", "clicked()", self.findChessBoardPattern )
        self.__gui.connect( "cmdCalibrateDistortion", "clicked()", self.calibrateCamera )
        self.__gui.connect( "cmdSaveDistortion", "clicked()", self.__saveConfiguration )
        self.__gui.connect( "cmdLoadDistortion", "clicked()", self.__loadConfiguration )
        self.__gui.connect( "chkCropImg", "toggled(bool)", self.__borderSelectionChanged )
        self.__gui.connect( "chkCropImgManual", "toggled(bool)", self.__borderSelectionChanged )

        # start timer
        self.__sceneImgTimer = QTimer()
        self.__sceneImgTimer.timeout.connect( self.__showImage )
        self.__sceneImgTimer.start(200)

    def isCalibrated(self):
        '''
        @return: True if image is calibrated
        '''
        return self.__calibrated

    def isCalibrating(self):
        '''
        @return: True if calibration is in progress
        '''
        return self.__calibrating

    def setImg(self, img=None):
        '''
        Sets current image
        '''
        self.__img = img
        self.__imgCounter += 1

    def __borderSelectionChanged(self):
        '''
        Checks selection of manual/auto
        border settings gui group
        '''
        if self.__gui.getObj("chkCropImgManual").isChecked():
            self.__gui.getObj("chkCropImg").setChecked(False)
            self.__gui.getObj("chkCropImg").setEnabled(False)
        else:
            self.__gui.getObj("chkCropImg").setEnabled(True)

        if self.__gui.getObj("chkCropImg").isChecked():
            self.__gui.getObj("chkCropImgManual").setChecked(False)
            self.__gui.getObj("chkCropImgManual").setEnabled(False)
        else:
            self.__gui.getObj("chkCropImgManual").setEnabled(True)

    def findChessBoardPattern(self):
        '''
        Finds maximum chessboard pattern
        '''
        # show message
        self.__imgScene = None
        self.__scene.clear()
        self.__scene.addSimpleText("Searching pattern...\nThis will take a while")
        self.__gview.show()

        # start search
        start_new_thread( self.__searchChessBoardPattern, () )

    def __searchChessBoardPattern(self):
        '''
        Searches for chessboard pattern
        (start in background)
        '''

        # get start and max values
        xStart = int( str( self.__gui.getObj("txtPatternXMin").text() ) )
        yStart =  int( str( self.__gui.getObj("txtPatternYMin").text() ) )
        xMax =  int( str( self.__gui.getObj("txtPatternXMax").text() ) )
        yMax =  int( str( self.__gui.getObj("txtPatternYMax").text() ) )

        # find pattern
        if self.__img != None:
            pattern = findChessBoardPatternSize(self.__img, xMax, yMax, xStart, yStart)

            if pattern != None and len(pattern) > 0:
                # set pattern
                if len(pattern) == 2:
                    self.__gui.getObj("txtPatternX").setText( str(pattern[0]) )
                    self.__gui.getObj("txtPatternY").setText( str(pattern[1]) )

    def calibrateCamera(self):
        '''
        Calibrates camera
        '''
        start_new_thread(self.__calibrate, ())

    def __calibrate(self):
        '''
        Calibrates camera
        (run in background)
        '''
        # check for correct image
        if self.__img != None:
            self.__calibrating = True
            self.__gui.status("Calibrating ...")

            # get values
            x = int(str( self.__gui.getObj("txtPatternX").text() ))
            y = int(str( self.__gui.getObj("txtPatternY").text() ))
            n = int(str( self.__gui.getObj("txtCalibrationFrames").text() ))
            square_size = float(str( self.__gui.getObj("txtCalibrationSquareSize").text() ))

            # calculate distortion
            pattern_size = (x, y)
            ret = self.__calibrateCorners(pattern_size, n, square_size)

            if ret != None:
                camera_matrix, dist_coefs = ret
                self.__camera_matrix, self.__dist_coefs = camera_matrix, dist_coefs

            # undistort image
            img = self.undistortImage(self.__img)
            self.__imgScene = img

            self.__gui.status("Searching for boders to crop image ...")

            # get corners
            if ret != None:
                found = False
                frames = 0;
                tries = 0;
                while not found and frames < n and tries < 10:
                    img = self.undistortImage(self.__img)
                    found, corners = getChessBoardCorners( img, pattern_size )
                    if found:
                        frames += 1
                    tries += 1

                if found:
                    self.__corners = getImageSizeFromCorners(corners)

            # crop image
            self.__imgScene = self.cropImage(img)
            self.__calibrated = True

        # set calibration flag
        self.__gui.status("Calibration finished.")

        self.__calibrating = False

    def __calibrateCorners(self, pattern_size, n, square_size):
        '''
        Calibrates corners of chessboard
        @return: camera_matrix, dist_coefs
        '''
        pattern_points = zeros( (prod(pattern_size), 3), float32 )
        pattern_points[:,:2] = indices(pattern_size).T.reshape(-1, 2)
        pattern_points *= square_size

        obj_points = []
        img_points = []
        frames = 0;
        tries = 0
        lastCount = self.__imgCounter;

        # detect pattern
        while frames < n and tries < 10:
            img = self.__img

            if lastCount != self.__imgCounter:
                # get corners
                found, corners = getChessBoardCorners( img, pattern_size )

                # check if corners found
                if found:
                    frames += 1

                    # get more detailed points and add them to list
                    img_points.append( corners.reshape(-1, 2) )
                    obj_points.append( pattern_points )

                    # draw corners
                    drawChessboardCorners( img, pattern_size, corners, found )
                    self.__imgScene = img
                    tries = 0
                tries += 1

        # get cmera values
        if img != None and len(obj_points) > 0 and len(img_points) > 0:
            return getCalibrationData(img, obj_points, img_points )

    def cropImage(self, img=None):
        '''
        Crops image if corners available
        @return: croped Image
        '''

        if self.__corners != None and img != None and ( self.__gui.getObj("chkCropImg").isChecked() or self.__gui.getObj("chkCropImgManual").isChecked() ) :

            # default settings for manual crop
            borderX = int( str(self.__gui.getObj("txtBorderLR").text()) )
            borderY = int( str(self.__gui.getObj("txtBorderTB").text()) )

            xmin = (img.shape[1]-1)/2 - borderX
            xmax = (img.shape[1]-1)/2 + borderX
            ymin = (img.shape[0]-1)/2 - borderY
            ymax = (img.shape[0]-1)/2 + borderY

            # settings for automatic crop
            if self.__gui.getObj("chkCropImg").isChecked():
                borders = int( float(str( self.__gui.getObj("txtCalibrationBorders").text() )) ) / 100.0
                borderX = int(img.shape[1] * borders)
                borderY = int(img.shape[0] * borders)

                xmin = int(self.__corners[0][0])
                xmax = int(self.__corners[0][1])
                ymin = int(self.__corners[1][0])
                ymax = int(self.__corners[1][1])

            # check new borders
            if xmin-borderX > 0:
                xmin = xmin-borderX
            else:
                xmin = 0

            if ymin-borderY > 0:
                ymin = ymin-borderY
            else:
                ymin = 0

            if xmax+borderX <= img.shape[1]:
                xmax = xmax+borderX
            else:
                xmax = img.shape[1]-1

            if ymax+borderY <= img.shape[0]:
                ymax = ymax+borderY
            else:
                ymax = img.shape[0]-1

            # conversion before
            if self.__gui.getObj("chkCropConvBefore").isChecked():
                img = cvtColor( img, COLOR_BGR2RGB )

            # crop image
            try:
                img = img[ymin:ymax, xmin:xmax]

                # conversion after
                img = cvtColor( img, COLOR_BGR2RGB )
            except:
                print "ERROR"

        return img

    def __showImage(self):
        '''
        Shows image
        '''
        if self.__imgScene != None:
            self.__scene.clear()
            self.__scene.addPixmap( imageToPixmap(self.__imgScene) )
            self.__gview.fitInView( self.__scene.sceneRect(), Qt.KeepAspectRatio )
            self.__gview.show()

    def undistortImage(self, img=None):
        '''
        Undistorts image
        @return: Image
        '''
        if self.__camera_matrix != None and self.__dist_coefs != None and img != None:
            return undistortImg( img, self.__camera_matrix, self.__dist_coefs )
        return img

    def __loadConfiguration(self):
        '''
        Loads configuration
        '''
        # stop video
        active = self.__imageGrabber.isActive()
        self.__imageGrabber.stopVideo()

        # get path
        options = copy(self.__gui.dialogOptionsDef)
        options['filetypes'] = "config file (*cfg)"
        src = str( self.__gui.dialog(options) )

        if len(src) > 0:
            # load file
            data = load( open(src, "rb") )

            if 'camera_matrix' in data:
                self.__camera_matrix = data['camera_matrix']
            if 'dist_coefs' in data:
                self.__dist_coefs = data['dist_coefs']
            if 'corners' in data:
                self.__corners = data['corners']
            if 'calibrated' in data:
                self.__calibrated = data['calibrated']
            if 'cropmanual' in data:
                self.__gui.getObj("chkCropImgManual").setChecked( data['cropmanual'] )
            if 'cropauto' in data:
                self.__gui.getObj("chkCropImg").setChecked( data['cropauto'] )
            if 'cropBorderLR' in data:
                self.__gui.getObj("txtBorderLR").setText( data['cropBorderLR'] )
            if 'cropBorderTB' in data:
                self.__gui.getObj("txtBorderTB").setText( data['cropBorderTB'] )
            if 'cropauto' in data:
                self.__gui.getObj("txtCalibrationBorders").setText( data['cropauto'] )
            if 'squareSize' in data:
                self.__gui.getObj("txtCalibrationSquareSize").setText( data['squareSize'] )
            if 'calibFrames' in data:
                self.__gui.getObj("txtCalibrationFrames").setText( data['calibFrames'] )
            if 'patternX' in data:
                self.__gui.getObj("txtPatternX").setText( data['patternX'] )
            if 'patternY' in data:
                self.__gui.getObj("txtPatternY").setText( data['patternY'] )

            self.__gui.status("Configuration loaded.")

        # restore video streaming mode
        if active:
            self.__imageGrabber.startVideo()

    def __saveConfiguration(self):
        '''
        Saves configuration
        '''
        # stop video
        active = self.__imageGrabber.isActive()
        self.__imageGrabber.stopVideo()

        options = copy(self.__gui.dialogOptionsDef)
        options['type'] = self.__gui.dialogTypes['FileSave']
        options['title'] = "Save configuration"
        options['filetypes'] = "Configuration (*cfg *mr)"
        src = str( self.__gui.dialog(options) )

        if len(src) > 0:
            # check path
            if not src.endswith(".cfg"):
                src += ".cfg"

            # save data to file
            data = {'camera_matrix': self.__camera_matrix,
                    'dist_coefs': self.__dist_coefs,
                    'corners': self.__corners,
                    'calibrated': self.__calibrated,
                    'cropmanual': self.__gui.getObj("chkCropImgManual").isChecked(),
                    'cropauto:': self.__gui.getObj("chkCropImg").isChecked(),
                    'cropBorder': str( self.__gui.getObj("txtCalibrationBorders").text() ),
                    'cropBorderLR': str( self.__gui.getObj("txtBorderLR").text() ),
                    'cropBorderTB': str( self.__gui.getObj("txtBorderTB").text() ),
                    'squareSize': str( self.__gui.getObj("txtCalibrationSquareSize").text() ),
                    'calibFrames': str( self.__gui.getObj("txtCalibrationFrames").text() ),
                    'patternX': str( self.__gui.getObj("txtPatternX").text() ),
                    'patternY': str( self.__gui.getObj("txtPatternY").text() )}

            dump( data, open(src, "wb") )
            self.__gui.status("Configuration saved to: " + src)

        # restore video streaming mode
        if active:
            self.__imageGrabber.startVideo()<|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
#
#
#    Copyright (C) 2015 Compassion CH (http://www.compassion.ch)
#    Releasing children from poverty in Jesus' name
#    @author: Emmanuel Mathier
#
#    The licence is in the file __openerp__.py
#

from openerp.osv import orm

class xmlrpc_helper(orm.Model):

    _inherit = "res.partner"

    def get_children_from_partner(self, cr, uid, partner_id, context=None):
        """
        return all child informations for all
        children from a partner_id specified
        """
        contract_obj = self.pool.get('recurring.contract')

        contract_ids = contract_obj.search(
            cr, uid, [('partner_id', '=', partner_id)], context=context)

        # get all child informations from each contract_id for each child
        children = list()
        for contract in contract_obj.browse(cr, uid, contract_ids, context):
            # contract must be linked to a child
            if contract.child_id:
                child = dict()
                child['id'] = contract.child_id.id
                child['code'] = contract.child_id.code
                child['type'] = contract.child_id.type
                child['state'] = contract.child_id.state
                child['firstname'] = contract.child_id.firstname
                child['name'] = contract.child_id.name
                child['gender'] = contract.child_id.gender
                child['birthdate'] = contract.child_id.birthdate
                child['desc_fr'] = contract.child_id.desc_fr
                child['desc_it'] = contract.child_id.desc_it
                child['desc_de'] = contract.child_id.desc_de
                child['desc_en'] = contract.child_id.desc_en
                children.append(child)

        return children

    def get_partner_from_user(self, cr, uid, context=None):
        """
        Attempt to login with username and password
        return all partner informations and user informations from
        """

        user_obj = self.pool.get('res.users')

        user = user_obj.browse(cr, uid, uid, context)

        partner = dict()
        partner['user_id'] = user.id
        partner['login'] = user.login
        partner['partner_id'] = user.partner_id.partner_id
        partner['ref'] = user.partner_id.ref
        partner['title'] = user.partner_id.title
        partner['is_company'] = user.partner_id.is_company
        partner['email'] = user.partner_id.email
        partner['phone'] = user.partner_id.phone
        partner['city'] = user.partner_id.city
        partner['zip'] = user.partner_id.zip
        partner['street'] = user.partner_id.street
        partner['street2'] = user.partner_id.street2
        partner['street3'] = user.partner_id.street3
        partner['firstname'] = user.partner_id.firstname
        partner['lastname'] = user.partner_id.lastname
        partner['lang'] = user.partner_id.lang

        return partner
<commit_msg>Dictionnaries syntax<commit_after># -*- encoding: utf-8 -*-
#
#
#    Copyright (C) 2015 Compassion CH (http://www.compassion.ch)
#    Releasing children from poverty in Jesus' name
#    @author: Emmanuel Mathier
#
#    The licence is in the file __openerp__.py
#

from openerp.osv import orm

class xmlrpc_helper(orm.Model):

    _inherit = "res.partner"

    def get_children_from_partner(self, cr, uid, partner_id, context=None):
        """
        return all child informations for all
        children from a partner_id specified
        """
        contract_obj = self.pool.get('recurring.contract')

        contract_ids = contract_obj.search(
            cr, uid, [('partner_id', '=', partner_id)], context=context)

        # get all child informations from each contract_id for each child
        children = list()
        for contract in contract_obj.browse(cr, uid, contract_ids, context):
            # contract must be linked to a child
            if contract.child_id:
                child = {
                    'id': contract.child_id.id,
                    'code': contract.child_id.code,
                    'type': contract.child_id.type,
                    'state': contract.child_id.state,
                    'firstname': contract.child_id.firstname,
                    'name': contract.child_id.name,
                    'gender': contract.child_id.gender,
                    'birthdate': contract.child_id.birthdate,
                    'desc_fr': contract.child_id.desc_fr,
                    'desc_it': contract.child_id.desc_it,
                    'desc_de': contract.child_id.desc_de,
                    'desc_en': contract.child_id.desc_en
                }
                children.append(child)

        return children

    def get_partner_from_user(self, cr, uid, args, context=None):
        """
        Attempt to login with username and password
        return all partner informations and user informations from
        """

        user_obj = self.pool.get('res.users')

        user = user_obj.browse(cr, uid, uid, context)

        partner = {
            'user_id': user.id,
            'login': user.login,
            'partner_id': user.partner_id.id,
            'ref': user.partner_id.ref,
            'title': user.partner_id.title.name,
            'is_company': user.partner_id.is_company,
            'email': user.partner_id.email,
            'phone': user.partner_id.phone,
            'city': user.partner_id.city,
            'zip': user.partner_id.zip,
            'street': user.partner_id.street,
            'street2': user.partner_id.street2,
            'street3': user.partner_id.street3,
            'firstname': user.partner_id.firstname,
            'lastname': user.partner_id.lastname,
            'lang': user.partner_id.lang
        }

        return partner
<|endoftext|>


<commit_before>#!/usr/bin/env python

import pytest

import jsonobject
from jsonobject import jsonproperty

class TestJSONSerializableObject(object):

    def test_default_getter(self):

        class SomeObject(jsonobject.JSONSerializableObject):
            # @jsonproperty creates a property which is exported to a
            # serialized JSON of SomeObject.
            # It can decorate without any arguments.
            @jsonproperty
            def foo(self):
                return 'FOO'

        s = SomeObject()
        # "foo" can be used as a normal getter.
        assert s.foo == 'FOO'
        # And is automatically exported.
        assert s.json() == '{"foo": "FOO"}'

    def test_named_getter(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # This field is exported as "field_foo".
            # Note that in @jsonproperty specs, parameters should be named; you
            # can't do this way:
            # @jsonproperty('field_foo')
            @jsonproperty(name='field_foo')
            def foo(self):
                return 'FOO'

        s = SomeObject()
        assert s.foo == 'FOO'
        assert s.json() == '{"field_foo": "FOO"}'

    def test_not_exported_if_omittable(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, value):
                self.value = value

            # If omittable is True, the property will not exported.
            # This is the default behavior if omitted.
            @jsonproperty(omittable=True)
            def foo(self):
                return self.value

        assert SomeObject('FOO').json() == '{"foo": "FOO"}'
        assert SomeObject('').json() == '{"foo": ""}'
        assert SomeObject(0).json() == '{"foo": 0}'
        assert SomeObject(None).json() == '{}'

    def test_exported_if_not_omittable(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, value):
                self.value = value

            # If omittable is False, the property will always be exported.
            @jsonproperty(omittable=False)
            def foo(self):
                return self.value

        assert SomeObject('FOO').json() == '{"foo": "FOO"}'
        assert SomeObject('').json() == '{"foo": ""}'
        assert SomeObject(0).json() == '{"foo": 0}'
        assert SomeObject(None).json() == '{"foo": null}'

    def test_non_primitive_value(self):
        class NonPrimitiveObject(object):
            pass

        class SomeObject(jsonobject.JSONSerializableObject):
            # The getter cannot return a non JSON primitive value.
            @jsonproperty
            def foo(self):
                return NonPrimitiveObject()

        with pytest.raises(TypeError):
            SomeObject().json()

    def test_non_primitive_serializable_value_getter(self):
        class NonPrimitiveSerializableObject(
                jsonobject.JSONSerializableObject):
            @jsonproperty
            def child_foo(self):
                return 'CHILD_FOO'

        class SomeObject(jsonobject.JSONSerializableObject):
            # OK if the non primitive value is JSON serializable.
            @jsonproperty
            def foo(self):
                return NonPrimitiveSerializableObject()

        assert SomeObject().json() == '{"foo": {"child_foo": "CHILD_FOO"}}'

    def test_setter_and_deleter(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, foo):
                self._foo = foo

            @jsonproperty
            def foo(self):
                return self._foo

            # Setter can be used just like the standard property.
            @foo.setter
            def foo(self, foo):
                self._foo = foo

            # The same for deleter. You should reset the value before caalling
            # json(), though.
            @foo.deleter
            def foo(self):
                del self._foo

        s = SomeObject('FOO')
        assert s.foo == 'FOO'
        assert s.json() == '{"foo": "FOO"}'
        s.foo = 'BAR'
        assert s.foo == 'BAR'
        assert s.json() == '{"foo": "BAR"}'
        del s.foo
        # Accessing a deleted property will raise AttributeError.
        with pytest.raises(AttributeError):
            s.foo
        # And trying to convert the container object to JSON will raise
        # TypeError.
        with pytest.raises(TypeError):
            s.json()
        # Resetting the property will make the conversion possible again.
        s.foo = "BAZ"
        assert s.json() == '{"foo": "BAZ"}'

    def test_json_property(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # This does the same thing as @jsonproperty getter, setter and
            # deleter.
            # Note that the JSON name is mandatory. It can be a positional
            # argument.
            foo = jsonobject.JSONProperty('foo')

        s = SomeObject()
        # The property defaults to None.
        assert s.foo is None
        s.foo = 'FOO'
        assert s.foo == 'FOO'
        assert s.json() == '{"foo": "FOO"}'
        # Deletion is not supported.
        with pytest.raises(AttributeError):
            del s.foo

    def test_json_property_default(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # default speficies the default value of the property.
            foo = jsonobject.JSONProperty('foo', default='FOO')

        s = SomeObject()
        assert s.foo == 'FOO'
        s.foo = 'BAR'
        assert s.foo == 'BAR'

    def test_json_property_init(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.JSONProperty('foo')
            bar = object()

        # JSONSerializableObject constructor accepts key-value specifications
        # for JSONProperty.
        s = SomeObject(foo='FOO')
        assert s.foo == 'FOO'
        # It doesn't accept setting a value to non-JSONProperty objects.
        with pytest.raises(AttributeError):
            s = SomeObject(bar='BAR')
        # It also rejects creating a new member.
        with pytest.raises(AttributeError):
            s = SomeObject(baz='BAZ')

    def test_json_property_not_shared_between_instances(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.JSONProperty('foo')

        s = SomeObject(foo='FOO')
        t = SomeObject(foo='BAR')
        assert s.foo == 'FOO'
        assert t.foo == 'BAR'

    def test_json_readonly_property(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, foo):
                self._foo = foo

            # This property exports SomeObject._foo in a readonly manner.
            foo = jsonobject.ReadonlyJSONProperty('foo', '_foo')

        s = SomeObject('FOO')
        assert s.foo == 'FOO'
        # Client code cannot assign a value to s.foo.
        with pytest.raises(AttributeError):
            s.foo = 'BAR'
        assert s.json('{"foo": "FOO"}')

    def test_readonly_json_property_init(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # If wrapped_variable is omitted, the property tries to wrap one
            # with a random unique name.
            foo = jsonobject.ReadonlyJSONProperty('foo', '_foo')
            # This is a class variable whose name conflicts with the wrapped
            # variable of foo.
            _foo = 'CLASS_FOO'

        # JSONSerializableObject constructor accepts key-value specifications
        # for ReadonlyJSONProperty too. It creates a private variable with the
        # name passed as the second argument (wrapped_variable).
        s = SomeObject(foo='FOO')
        assert s.foo == 'FOO'
        assert s._foo == 'FOO'
        # There is a class variable whose name conflicts with that.
        # JSONSerializableObject's constructor never overwrite the class
        # variable, but you may want to avoid these situations, as it looks
        # very weird. (Of course, that looks like a design flaw to begin with.)
        assert SomeObject._foo == 'CLASS_FOO'

    def test_readonly_json_property_default(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.ReadonlyJSONProperty('foo', default='FOO')

        assert SomeObject().foo == 'FOO'
        assert SomeObject(foo='BAR').foo == 'BAR'

    def test_readonly_json_property_not_shared_between_instances(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.ReadonlyJSONProperty('foo')

        s = SomeObject(foo='FOO')
        t = SomeObject(foo='BAR')
        assert s.foo == 'FOO'
        assert t.foo == 'BAR'

    def test_nested_jsonobject(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            a = jsonobject.JSONProperty('a', default='A')
            b = jsonobject.ReadonlyJSONProperty('b', default='B')

            @jsonproperty
            def c(self):
                return 'C'

        # You can create a nested class from another serializable object class.
        class AnotherObject(SomeObject):
            d = jsonobject.JSONProperty('d', default='D')
            e = jsonobject.ReadonlyJSONProperty('e', default='E')

            @jsonproperty
            def f(self):
                return 'F'

        s = SomeObject()
        assert s.json(sort_keys=True) == '{"a": "A", "b": "B", "c": "C"}'
        t = AnotherObject()
        assert t.json(sort_keys=True) == ('{"a": "A", "b": "B", "c": "C", '
                                          '"d": "D", "e": "E", "f": "F"}')
        # You can initialize superclass' properties as well.
        # Note that, however, properties created by @jsonproperty is not
        # initializable from this syntax.
        u = AnotherObject(a="AA", b="BB", d="DD", e="EE")
        assert u.json(sort_keys=True) == ('{"a": "AA", "b": "BB", "c": "C", '
                                          '"d": "DD", "e": "EE", "f": "F"}')

    def test_overriding_jsonobject(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            a = jsonobject.JSONProperty('a', default='A')
            b = jsonobject.JSONProperty('b', default='B')

            def update_a(self, value):
                self.a = value

        class AnotherObject(SomeObject):
            # You can override some properties exported by the superclass.
            a = jsonobject.JSONProperty('a', default='AA')

        s = SomeObject()
        assert s.json(sort_keys=True) == '{"a": "A", "b": "B"}'
        t = AnotherObject()
        assert t.json(sort_keys=True) == '{"a": "AA", "b": "B"}'
        t.update_a('AAA')
        assert t.json(sort_keys=True) == '{"a": "AAA", "b": "B"}'
        u = AnotherObject(a='AAAA', b='BBBB')
        assert u.json(sort_keys=True) == '{"a": "AAAA", "b": "BBBB"}'

    def test_instance_json_property(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # Though it's not recommended for most use cases, JSON properties
            # can be created dynamically at instance creation time.
            # This is sometimes useful for dynamically importing unknown JSON
            # but do not abuse this. This is tricky. For readability, an
            # ordinary property should be explicitly declared at the class
            # level.
            def __init__(self, **kwargs):
                # Dynamically create a new type, because properties
                # (to be precise, descriptors) works if and only if owned by a
                # class object.
                cls = type('__{}_{}'.format(self.__class__.__name__, id(self)),
                           (jsonobject.JSONSerializableObject,),
                           dict(self.__class__.__dict__))
                # Change the class of this instance.
                self.__class__ = cls
                # Create properties dynamically and add to the dynamically
                # created class.
                cls.foo = jsonobject.JSONProperty('foo', default='FOO')
                cls.bar = jsonobject.ReadonlyJSONProperty('bar', default='BAR')
                # And from kwargs. You may want to import JSON in this way.
                for key, value in kwargs.iteritems():
                    if not hasattr(cls, key):
                        setattr(cls, key, jsonobject.JSONProperty(key))
                # Set the value using JSONSerializableObject's constructor.
                super(cls, self).__init__(**kwargs)

            # Note that, this class level property will be present in the new
            # dynamically created class, because of self.__clas__.__dict__ is
            # passed to type() above.
            baz = jsonobject.JSONProperty('baz', default='BAZ')

        s = SomeObject(foo='FOOFOO', qux='QUX', quux='QUUX')
        assert s.foo == 'FOOFOO'
        assert s.bar == 'BAR'
        with pytest.raises(AttributeError):
            s.bar = 'BARBAR'
        assert s.baz == 'BAZ'
        assert s.qux == 'QUX'
        assert s.quux == 'QUUX'
        assert s.json(sort_keys=True) == ('{"bar": "BAR", "baz": "BAZ", '
                                          '"foo": "FOOFOO", "quux": "QUUX", '
                                          '"qux": "QUX"}')

    def test_instance_json_property_simple(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # This is a bit simple version of dynamic property creation.
            # This way the class definition is much simpler...
            def __init__(self, **kwargs):
                super(SomeObject, self).__init__(**kwargs)
                # bar is a dynamically created property.
                self.bar = jsonobject.JSONProperty('bar', default='BAR')

            foo = jsonobject.JSONProperty('foo', default='FOO')

        s = SomeObject()
        assert s.foo == 'FOO'
        # However, you cannot manipulate bar naturally.
        # You would call __get__(), __set__() to directly talk with this
        # property (descriptor) object.
        assert s.bar.__get__(s) == 'BAR'
        # Serializing to JSON is still straightforward.
        assert s.json(sort_keys=True) == '{"bar": "BAR", "foo": "FOO"}'

def main():
    import doctest
    doctest.testmod(jsonobject)
    pytest.main(args=[__file__.replace('.pyc', '.py')])

if __name__ == '__main__':
    main()
<commit_msg>Add an bad example of dynamic property using a shared class object.<commit_after>#!/usr/bin/env python

import pytest

import jsonobject
from jsonobject import jsonproperty

class TestJSONSerializableObject(object):

    def test_default_getter(self):

        class SomeObject(jsonobject.JSONSerializableObject):
            # @jsonproperty creates a property which is exported to a
            # serialized JSON of SomeObject.
            # It can decorate without any arguments.
            @jsonproperty
            def foo(self):
                return 'FOO'

        s = SomeObject()
        # "foo" can be used as a normal getter.
        assert s.foo == 'FOO'
        # And is automatically exported.
        assert s.json() == '{"foo": "FOO"}'

    def test_named_getter(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # This field is exported as "field_foo".
            # Note that in @jsonproperty specs, parameters should be named; you
            # can't do this way:
            # @jsonproperty('field_foo')
            @jsonproperty(name='field_foo')
            def foo(self):
                return 'FOO'

        s = SomeObject()
        assert s.foo == 'FOO'
        assert s.json() == '{"field_foo": "FOO"}'

    def test_not_exported_if_omittable(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, value):
                self.value = value

            # If omittable is True, the property will not exported.
            # This is the default behavior if omitted.
            @jsonproperty(omittable=True)
            def foo(self):
                return self.value

        assert SomeObject('FOO').json() == '{"foo": "FOO"}'
        assert SomeObject('').json() == '{"foo": ""}'
        assert SomeObject(0).json() == '{"foo": 0}'
        assert SomeObject(None).json() == '{}'

    def test_exported_if_not_omittable(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, value):
                self.value = value

            # If omittable is False, the property will always be exported.
            @jsonproperty(omittable=False)
            def foo(self):
                return self.value

        assert SomeObject('FOO').json() == '{"foo": "FOO"}'
        assert SomeObject('').json() == '{"foo": ""}'
        assert SomeObject(0).json() == '{"foo": 0}'
        assert SomeObject(None).json() == '{"foo": null}'

    def test_non_primitive_value(self):
        class NonPrimitiveObject(object):
            pass

        class SomeObject(jsonobject.JSONSerializableObject):
            # The getter cannot return a non JSON primitive value.
            @jsonproperty
            def foo(self):
                return NonPrimitiveObject()

        with pytest.raises(TypeError):
            SomeObject().json()

    def test_non_primitive_serializable_value_getter(self):
        class NonPrimitiveSerializableObject(
                jsonobject.JSONSerializableObject):
            @jsonproperty
            def child_foo(self):
                return 'CHILD_FOO'

        class SomeObject(jsonobject.JSONSerializableObject):
            # OK if the non primitive value is JSON serializable.
            @jsonproperty
            def foo(self):
                return NonPrimitiveSerializableObject()

        assert SomeObject().json() == '{"foo": {"child_foo": "CHILD_FOO"}}'

    def test_setter_and_deleter(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, foo):
                self._foo = foo

            @jsonproperty
            def foo(self):
                return self._foo

            # Setter can be used just like the standard property.
            @foo.setter
            def foo(self, foo):
                self._foo = foo

            # The same for deleter. You should reset the value before caalling
            # json(), though.
            @foo.deleter
            def foo(self):
                del self._foo

        s = SomeObject('FOO')
        assert s.foo == 'FOO'
        assert s.json() == '{"foo": "FOO"}'
        s.foo = 'BAR'
        assert s.foo == 'BAR'
        assert s.json() == '{"foo": "BAR"}'
        del s.foo
        # Accessing a deleted property will raise AttributeError.
        with pytest.raises(AttributeError):
            s.foo
        # And trying to convert the container object to JSON will raise
        # TypeError.
        with pytest.raises(TypeError):
            s.json()
        # Resetting the property will make the conversion possible again.
        s.foo = "BAZ"
        assert s.json() == '{"foo": "BAZ"}'

    def test_json_property(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # This does the same thing as @jsonproperty getter, setter and
            # deleter.
            # Note that the JSON name is mandatory. It can be a positional
            # argument.
            foo = jsonobject.JSONProperty('foo')

        s = SomeObject()
        # The property defaults to None.
        assert s.foo is None
        s.foo = 'FOO'
        assert s.foo == 'FOO'
        assert s.json() == '{"foo": "FOO"}'
        # Deletion is not supported.
        with pytest.raises(AttributeError):
            del s.foo

    def test_json_property_default(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # default speficies the default value of the property.
            foo = jsonobject.JSONProperty('foo', default='FOO')

        s = SomeObject()
        assert s.foo == 'FOO'
        s.foo = 'BAR'
        assert s.foo == 'BAR'

    def test_json_property_init(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.JSONProperty('foo')
            bar = object()

        # JSONSerializableObject constructor accepts key-value specifications
        # for JSONProperty.
        s = SomeObject(foo='FOO')
        assert s.foo == 'FOO'
        # It doesn't accept setting a value to non-JSONProperty objects.
        with pytest.raises(AttributeError):
            s = SomeObject(bar='BAR')
        # It also rejects creating a new member.
        with pytest.raises(AttributeError):
            s = SomeObject(baz='BAZ')

    def test_json_property_not_shared_between_instances(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.JSONProperty('foo')

        s = SomeObject(foo='FOO')
        t = SomeObject(foo='BAR')
        assert s.foo == 'FOO'
        assert t.foo == 'BAR'

    def test_json_readonly_property(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            def __init__(self, foo):
                self._foo = foo

            # This property exports SomeObject._foo in a readonly manner.
            foo = jsonobject.ReadonlyJSONProperty('foo', '_foo')

        s = SomeObject('FOO')
        assert s.foo == 'FOO'
        # Client code cannot assign a value to s.foo.
        with pytest.raises(AttributeError):
            s.foo = 'BAR'
        assert s.json('{"foo": "FOO"}')

    def test_readonly_json_property_init(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # If wrapped_variable is omitted, the property tries to wrap one
            # with a random unique name.
            foo = jsonobject.ReadonlyJSONProperty('foo', '_foo')
            # This is a class variable whose name conflicts with the wrapped
            # variable of foo.
            _foo = 'CLASS_FOO'

        # JSONSerializableObject constructor accepts key-value specifications
        # for ReadonlyJSONProperty too. It creates a private variable with the
        # name passed as the second argument (wrapped_variable).
        s = SomeObject(foo='FOO')
        assert s.foo == 'FOO'
        assert s._foo == 'FOO'
        # There is a class variable whose name conflicts with that.
        # JSONSerializableObject's constructor never overwrite the class
        # variable, but you may want to avoid these situations, as it looks
        # very weird. (Of course, that looks like a design flaw to begin with.)
        assert SomeObject._foo == 'CLASS_FOO'

    def test_readonly_json_property_default(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.ReadonlyJSONProperty('foo', default='FOO')

        assert SomeObject().foo == 'FOO'
        assert SomeObject(foo='BAR').foo == 'BAR'

    def test_readonly_json_property_not_shared_between_instances(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            foo = jsonobject.ReadonlyJSONProperty('foo')

        s = SomeObject(foo='FOO')
        t = SomeObject(foo='BAR')
        assert s.foo == 'FOO'
        assert t.foo == 'BAR'

    def test_nested_jsonobject(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            a = jsonobject.JSONProperty('a', default='A')
            b = jsonobject.ReadonlyJSONProperty('b', default='B')

            @jsonproperty
            def c(self):
                return 'C'

        # You can create a nested class from another serializable object class.
        class AnotherObject(SomeObject):
            d = jsonobject.JSONProperty('d', default='D')
            e = jsonobject.ReadonlyJSONProperty('e', default='E')

            @jsonproperty
            def f(self):
                return 'F'

        s = SomeObject()
        assert s.json(sort_keys=True) == '{"a": "A", "b": "B", "c": "C"}'
        t = AnotherObject()
        assert t.json(sort_keys=True) == ('{"a": "A", "b": "B", "c": "C", '
                                          '"d": "D", "e": "E", "f": "F"}')
        # You can initialize superclass' properties as well.
        # Note that, however, properties created by @jsonproperty is not
        # initializable from this syntax.
        u = AnotherObject(a="AA", b="BB", d="DD", e="EE")
        assert u.json(sort_keys=True) == ('{"a": "AA", "b": "BB", "c": "C", '
                                          '"d": "DD", "e": "EE", "f": "F"}')

    def test_overriding_jsonobject(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            a = jsonobject.JSONProperty('a', default='A')
            b = jsonobject.JSONProperty('b', default='B')

            def update_a(self, value):
                self.a = value

        class AnotherObject(SomeObject):
            # You can override some properties exported by the superclass.
            a = jsonobject.JSONProperty('a', default='AA')

        s = SomeObject()
        assert s.json(sort_keys=True) == '{"a": "A", "b": "B"}'
        t = AnotherObject()
        assert t.json(sort_keys=True) == '{"a": "AA", "b": "B"}'
        t.update_a('AAA')
        assert t.json(sort_keys=True) == '{"a": "AAA", "b": "B"}'
        u = AnotherObject(a='AAAA', b='BBBB')
        assert u.json(sort_keys=True) == '{"a": "AAAA", "b": "BBBB"}'

    def test_instance_json_property(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # Though it's not recommended for most use cases, JSON properties
            # can be created dynamically at instance creation time.
            # This is sometimes useful for dynamically importing unknown JSON
            # but do not abuse this. This is tricky. For readability, an
            # ordinary property should be explicitly declared at the class
            # level.
            def __init__(self, **kwargs):
                # Dynamically create a new type, because properties
                # (to be precise, descriptors) works if and only if owned by a
                # class object.
                cls = type('__{}_{}'.format(self.__class__.__name__, id(self)),
                           (jsonobject.JSONSerializableObject,),
                           dict(self.__class__.__dict__))
                # Change the class of this instance.
                self.__class__ = cls
                # Create properties dynamically and add to the dynamically
                # created class.
                cls.foo = jsonobject.JSONProperty('foo', default='FOO')
                cls.bar = jsonobject.ReadonlyJSONProperty('bar', default='BAR')
                # And from kwargs. You may want to import JSON in this way.
                for key, value in kwargs.iteritems():
                    if not hasattr(cls, key):
                        setattr(cls, key, jsonobject.JSONProperty(key))
                # Set the value using JSONSerializableObject's constructor.
                super(cls, self).__init__(**kwargs)

            # Note that, this class level property will be present in the new
            # dynamically created class, because of self.__clas__.__dict__ is
            # passed to type() above.
            baz = jsonobject.JSONProperty('baz', default='BAZ')

        s = SomeObject(foo='FOOFOO', qux='QUX', quux='QUUX')
        assert s.foo == 'FOOFOO'
        assert s.bar == 'BAR'
        with pytest.raises(AttributeError):
            s.bar = 'BARBAR'
        assert s.baz == 'BAZ'
        assert s.qux == 'QUX'
        assert s.quux == 'QUUX'
        assert s.json(sort_keys=True) == ('{"bar": "BAR", "baz": "BAZ", '
                                          '"foo": "FOOFOO", "quux": "QUUX", '
                                          '"qux": "QUX"}')

    def test_instance_json_property_shared_class(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # Do not do something like this!
            # This is a bad example of a dynamic property, where I store a
            # property to a shared class object, which will produce a side
            # effect for other instances.
            def __init__(self, **kwargs):
                cls = self.__class__
                # Create properties dynamically and add to the shared class
                # object.
                for key, value in kwargs.iteritems():
                    if not hasattr(cls, key):
                        setattr(cls, key, jsonobject.JSONProperty(
                            key, default=value))
                # Set the value using JSONSerializableObject's constructor.
                super(cls, self).__init__(**kwargs)

            baz = jsonobject.JSONProperty('baz', default='BAZ')

        s = SomeObject(foo='FOO')
        # This is expected...
        assert s.foo == 'FOO'
        assert s.baz == 'BAZ'
        assert s.json(sort_keys=True) == '{"baz": "BAZ", "foo": "FOO"}'
        # Also this is fine...
        t = SomeObject(bar='BAR')
        assert t.bar == 'BAR'
        assert t.baz == 'BAZ'
        # But what is this?! Why do I have foo here though I don't define it
        # for t!
        assert t.foo == 'FOO'
        assert t.json(sort_keys=True) == ('{"bar": "BAR", "baz": "BAZ", '
                                          '"foo": "FOO"}')
        # That's why I put a property to the shared class object.
        # So, use a dynamic class object like what's in
        # test_instance_json_property. (But to begin with, avoid using a
        # dynamic property as much as possible.)

    def test_instance_json_property_simple(self):
        class SomeObject(jsonobject.JSONSerializableObject):
            # This is a bit simple version of dynamic property creation.
            # This way the class definition is much simpler...
            def __init__(self, **kwargs):
                super(SomeObject, self).__init__(**kwargs)
                # bar is a dynamically created property.
                self.bar = jsonobject.JSONProperty('bar', default='BAR')

            foo = jsonobject.JSONProperty('foo', default='FOO')

        s = SomeObject()
        assert s.foo == 'FOO'
        # However, you cannot manipulate bar naturally.
        # You would call __get__(), __set__() to directly talk with this
        # property (descriptor) object.
        assert s.bar.__get__(s) == 'BAR'
        # Serializing to JSON is still straightforward.
        assert s.json(sort_keys=True) == '{"bar": "BAR", "foo": "FOO"}'

def main():
    import doctest
    doctest.testmod(jsonobject)
    pytest.main(args=[__file__.replace('.pyc', '.py')])

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


<commit_before># coding: utf-8
'''
Created on 2014年7月23日

@author: lunatic
'''
import json
from lexer import Lexer, TAG

class Parser(object):

    def __init__(self, text):
        self.lexer = Lexer(text)
        self.move()

    def move(self):
        self.token = self.lexer.scan()
        print self.token

    def program(self):
        ret = self.parse()
        if self.token != None:
            self.error('Expecting \'EOF\'')
        return ret

    def parse(self):
        if self.is_open_brace():
            return self.obj()
        if self.is_open_bracket():
            return self.arr()

        self.error('Expect \'{\' or \'[\'')

    def match(self, __type):
        if self.token._type == __type:
            self.move()
        else:self.error('Expect \'%s\'' % TAG.MAP[__type])

    def obj(self):
        ret_dict = {}
        self.match(TAG.OPEN_BRACE)
        #Note: Mybe, Object is empty
        if self.is_close_brace():
            self.match(TAG.CLOSE_BRACE)
            return ret_dict

        while not self.is_close_brace():
            key, val = self.pair()
            ret_dict[key] = val
            if self.is_sep():
                self.match(TAG.COMMA)
            else:
                break

        self.match(TAG.CLOSE_BRACE)
        return ret_dict

    def arr(self):
        ret_list = []
        self.match(TAG.OPEN_BRACKET)
        #Note: Mybe, list is empty
        if self.is_close_bracket():
            self.match(TAG.CLOSE_BRACKET)
            return ret_list

        while True:
            val = self.value()
            ret_list.append(val)
            if self.is_sep():
                self.match(TAG.COMMA)
            else:
                break

        self.match(TAG.CLOSE_BRACKET)
        return ret_list

    # "name":"hzzhenglh", ....
    def pair(self):
        key = self.token.content
        self.match(TAG.KEY)
        self.match(TAG.COLON)  # :
        val = self.value()
        return (key, val)

    def value(self):
        if self.is_val():
            content = self.token.content
            self.move()
            return content
        else:return self.parse()

    def is_sep(self):
        return self.token._type == TAG.COMMA

    def is_open_brace(self):
        return self.token._type == TAG.OPEN_BRACE
    def is_open_bracket(self):
        return self.token._type == TAG.OPEN_BRACKET
    def is_close_brace(self):
        return self.token._type == TAG.CLOSE_BRACE
    def is_close_bracket(self):
        return self.token._type == TAG.CLOSE_BRACKET
    def is_val(self):
        """
        string, number, false, true, null,
        """
        return  self.token._type == TAG.BOOLEAN or\
                self.token._type == TAG.NUMBER or\
                self.token._type == TAG.STRING or\
                self.token._type == TAG.NULL

    def error(self, msg):
        raise Exception('Syntax error: %s (%s)' % (msg, self.token.pos))

def main():
    #text = "{\"firstName\":\"Brett\",\"lastName\":\"McLaughlin\",\"email\":\"aaaa\", \"age\":18, \"sex\":true, \"wife\":null}";

    with open("test.json") as f:
        text = '\n'.join(f.readlines())

    ret = Parser(text).program()
    print ret
    print json.dumps(ret)

if __name__ == '__main__':
    main()<commit_msg>modify error info<commit_after># coding: utf-8
'''
Created on 2014年7月23日

@author: lunatic
'''
import json
from lexer import Lexer, TAG

class Parser(object):

    def __init__(self, text):
        self.lexer = Lexer(text)
        self.move()

    def move(self):
        self.token = self.lexer.scan()
        print self.token

    def program(self):
        ret = self.parse()
        if self.token != None:
            self.error('Expecting "EOF"')
        return ret

    def parse(self):
        if self.is_open_brace():
            return self.obj()
        if self.is_open_bracket():
            return self.arr()

        self.error('Expect "{" or "["')

    def match(self, __type):
        if self.token._type == __type:
            self.move()
        else:self.error('Expect "%s"' % TAG.MAP[__type])

    def obj(self):
        ret_dict = {}
        self.match(TAG.OPEN_BRACE)
        #Note: Mybe, Object is empty
        if self.is_close_brace():
            self.match(TAG.CLOSE_BRACE)
            return ret_dict

        while not self.is_close_brace():
            key, val = self.pair()
            ret_dict[key] = val
            if self.is_sep():
                self.match(TAG.COMMA)
            else:
                break

        self.match(TAG.CLOSE_BRACE)
        return ret_dict

    def arr(self):
        ret_list = []
        self.match(TAG.OPEN_BRACKET)
        #Note: Mybe, list is empty
        if self.is_close_bracket():
            self.match(TAG.CLOSE_BRACKET)
            return ret_list

        while True:
            val = self.value()
            ret_list.append(val)
            if self.is_sep():
                self.match(TAG.COMMA)
            else:
                break

        self.match(TAG.CLOSE_BRACKET)
        return ret_list

    # "name":"hzzhenglh", ....
    def pair(self):
        key = self.token.content
        self.match(TAG.KEY)
        self.match(TAG.COLON)  # :
        val = self.value()
        return (key, val)

    def value(self):
        if self.is_val():
            content = self.token.content
            self.move()
            return content
        else:return self.parse()

    def is_sep(self):
        return self.token._type == TAG.COMMA

    def is_open_brace(self):
        return self.token._type == TAG.OPEN_BRACE
    def is_open_bracket(self):
        return self.token._type == TAG.OPEN_BRACKET
    def is_close_brace(self):
        return self.token._type == TAG.CLOSE_BRACE
    def is_close_bracket(self):
        return self.token._type == TAG.CLOSE_BRACKET
    def is_val(self):
        """
        string, number, false, true, null,
        """
        return  self.token._type == TAG.BOOLEAN or\
                self.token._type == TAG.NUMBER or\
                self.token._type == TAG.STRING or\
                self.token._type == TAG.NULL

    def error(self, msg):
        raise Exception('Syntax error: %s (%s)' % (msg, self.token.pos))

def main():
    #text = "{\"firstName\":\"Brett\",\"lastName\":\"McLaughlin\",\"email\":\"aaaa\", \"age\":18, \"sex\":true, \"wife\":null}";

    with open("test.json") as f:
        text = '\n'.join(f.readlines())

    ret = Parser(text).program()
    print ret
    print json.dumps(ret)

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