Commit 8956bbf9 authored by Yori Fournier's avatar Yori Fournier
Browse files

Merge branch '63-cleaning-server-client-renovation' into 'dev'

Resolve "CLEANING: Server/Client renovation"

Closes #63

See merge request !44
parents 6fef4dab 8d7accf3
Pipeline #403 failed with stage
in 1 minute and 23 seconds
myplotlib_server_client:
script:
- apt-get update -q -y
- apt-get install python-dev -q -y
- wget https://bootstrap.pypa.io/get-pip.py
- python get-pip.py
- python -m pip --version
- python -m pip install --upgrade pip
- python -m pip install -U matplotlib
- git clone git@gitlab.aip.de:yfournier/myplotlib.git -b 63-cleaning-server-client-renovation myplotlib
- cd myplotlib/test/localhost
- ./setup_test_folder.sh
- python import_test.py
- ./clean_test_folder.sh
...@@ -34,72 +34,153 @@ ...@@ -34,72 +34,153 @@
# #
# IMPORT --------------------------------------------------------------- # IMPORT ---------------------------------------------------------------
from .config import INFO, WARN, SEVR, DBUG, SPCE from .config import INFO, WARN, SEVR, DBUG, SPCE
from .config import D_HIERARCHY
import os as os import os as os
import numpy as np import numpy as np
np.set_printoptions(threshold='nan')
# Test mpl version: from signal import Signal, Query, Status, Answer
from matplotlib import __version__ as mplvers from mpl_unpickler import MplUnpickler
if int(mplvers.replace('.','')[:3]) < 143 : # matplotlib import for client/local -----------------------------------
if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
if D_HIERARCHY in ('CLIENT', 'client'):
print(INFO+'Import '+__package__+' as a client.')
else:
print(INFO+'Import '+__package__+' for local use.')
# Test mpl version:
from matplotlib import __version__ as mplvers
if int(mplvers.replace('.','')[:3]) < 143 :
print('\n\n' + WARN + 72*'=' + '\n' + SPCE + 'The matplotlib version you are using is not supported.\n' + SPCE + 'Most of myplotlib should work, but some stuff may not.\n' + SPCE + 'ex: expect an error with test203\n' + SPCE + 72*'=' + '\n\n') print('\n\n' + WARN + 72*'=' + '\n' + SPCE + 'The matplotlib version you are using is not supported.\n' + SPCE + 'Most of myplotlib should work, but some stuff may not.\n' + SPCE + 'ex: expect an error with test203\n' + SPCE + 72*'=' + '\n\n')
# matplotlib # matplotlib
from matplotlib.pyplot import figure from matplotlib.pyplot import figure
from matplotlib.pyplot import rc from matplotlib.pyplot import rc
from matplotlib.pyplot import show, draw, ion, ioff, clf from matplotlib.pyplot import show, draw, ion, ioff, clf
from matplotlib.pyplot import close as mpclose from matplotlib.pyplot import close as mpclose
from matplotlib.pyplot import fignum_exists, savefig from matplotlib.pyplot import fignum_exists, savefig
from matplotlib.axes import Axes from matplotlib.axes import Axes
from matplotlib.figure import Figure from matplotlib.figure import Figure
from matplotlib import is_interactive from matplotlib import is_interactive
#from matplotlib import rcParams from matplotlib import use
from matplotlib import use
from .config import D_HOST, D_PORT
from socket import socket, AF_INET, SOCK_STREAM
elif D_HIERARCHY in ('SERVER', 'server'):
print(INFO+'Import '+__package__+' as a server.')
from .config import D_HOST, D_PORT
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
else:
print(SEVR+'the value of D_HIERARCHY has to be SERVER or CLIENT')
raise ImportError
# myplotlib # myplotlib
from .myData import MyData from .myData import MyData
# GLOBAL VARIABLE ------------------------------------------------------
G_RAWDATAS = {'current': MyData()} # raw data Object
_G_WINDOWS = []
# CONFIGURATION -------------------------------------------------------- # CONFIGURATION --------------------------------------------------------
from .config import D_FIGNUM, D_FIGSIZE, D_REFORMAT, D_FORMATTED from .config import D_FIGNUM, D_FIGSIZE, D_REFORMAT, D_FORMATTED
from .config import D_RAWDATA, D_INPUTARG from .config import D_RAWDATA, D_INPUTARG
from .config import D_IPATH from .config import D_IPATH
from .config import D_OPATH, D_OFORMAT from .config import D_OPATH, D_OFORMAT
from .config import D_DEBUG from .config import D_DEBUG
from .config import rcParams
# FUNCTIONS ------------------------------------------------------------ if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes import MyAxes from .rconfig import rcParams
if D_HIERARCHY in ('CLIENT', 'client'):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes_client import MyAxes_client as MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig_client import MyFig_client as MyFig
from .progressbar import ProgressBar
from .mplClient import MplClient
from .mplClient2 import MplClient2
elif(D_HIERARCHY in ('SERVER', 'server')):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes_server import MyAxes_server as MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig_server import MyFig_server as MyFig
# MyFig: Overlay on matplotlib.Figure class # from .test import FigTestServer
from .myFig import MyFig # from .test import FigTest
# MyFig: Overlay on matplotlib.FigureManager class # for testing purpose
if rcParams['backend'] == u'TkAgg': # from .test import readStupidData, readStupidData2
SERVER_IOFUNCTIONS = {
# 'readStupidData': readStupidData,
# 'readStupidData2': readStupidData2
}
SERVER_FIGURES = {
#'FigTest': FigTest
}
from .mplServer import MplServer
from .mplServer2 import MplServer2, MplHandler
elif D_HIERARCHY in ('LOCAL', 'local'):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes import MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig import MyFig
else:
print(SEVR+'the value of D_HIERARCHY has to be SERVER, CLIENT or LOCAL')
raise ImportError
if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
_G_WINDOWS = []
# MyWin: Overlay on matplotlib.FigureManager class
if rcParams['backend'] == u'TkAgg':
from .myWin_TkAgg import MyWin_TkAgg as MyWin from .myWin_TkAgg import MyWin_TkAgg as MyWin
elif rcParams['backend'] == u'GTKAgg': elif rcParams['backend'] == u'GTKAgg':
from .myWin_GTKAgg import MyWin_GTKAgg as MyWin from .myWin_GTKAgg import MyWin_GTKAgg as MyWin
elif rcParams['backend'] == u'WXAgg': elif rcParams['backend'] == u'WXAgg':
from .myWin_WXAgg import MyWin_WXAgg as MyWin from .myWin_WXAgg import MyWin_WXAgg as MyWin
elif rcParams['backend'] == u'Qt4Agg': elif rcParams['backend'] == u'Qt4Agg':
from .myWin_Qt4Agg import MyWin_Qt4Agg as MyWin from .myWin_Qt4Agg import MyWin_Qt4Agg as MyWin
elif rcParams['backend'] == u'MacOSX': elif rcParams['backend'] == u'MacOSX':
from .myWin_MacOSx import MyWin_MacOSx as MyWin from .myWin_MacOSx import MyWin_MacOSx as MyWin
else: else:
print(SEVR + "The backend you choosed is not supported interactive mode not available") print(SEVR + "The backend you choosed is not supported interactive mode not available")
# myTool.*: interface functions to use myplotlib interactively # myTool.*: interface functions to use myplotlib interactively
from .mytool import window_exists, getCurrentWindowIDs #from .mytool import print2file # need to make tools for server ?? or just put them in client/local
from .mytool import print2file, print2screen, printListCurrentWindows #from .mytool import FigOneAxes
from .mytool import getWindow, getFigOnWindow, drawFigOnWindow, giveDataToWindow
from .mytool import closeWindow, closeAllWindows #if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
from .mytool import FigOneAxes
# from .mytool import print2file # need to make tools for server ?? or just put them in client/local
# from .mytool import FigOneAxes
# from .mytool import window_exists, getCurrentWindowIDs
# from .mytool import print2file, print2screen, printListCurrentWindows
# from .mytool import getWindow, getFigOnWindow, drawFigOnWindow, giveDataToWindow
# from .mytool import closeWindow, closeAllWindows
# TESTS ----------------------------------------------------------------
# from .test import myTest
# from .test import testList
# from .test import FigTest
from .test import myTest
# import the tests
from .test import testList
...@@ -31,9 +31,15 @@ ...@@ -31,9 +31,15 @@
# #
# #
# IMPORT --------------------------------------------------------------- # IMPORT ---------------------------------------------------------------
from . import D_HIERARCHY
from . import INFO, SPCE, DBUG from . import INFO, SPCE, DBUG
from . import myTest, testList
from .test import __dict__ as availTests if D_HIERARCHY in ('CLIENT', 'client', 'local', 'LOCAL'):
from . import myTest, testList
from .test import __dict__ as availTests
else:
from socket import socket, AF_INET, SOCK_STREAM
from . import D_HOST, D_PORT
import sys import sys
import getopt import getopt
...@@ -56,7 +62,7 @@ usage = ''' ...@@ -56,7 +62,7 @@ usage = '''
# GET OPT # GET OPT
try: try:
opts, args = getopt.getopt( opts, args = getopt.getopt(
sys.argv[1:], "htp:", ["test=", "plot=", "args=", "debug"]) sys.argv[1:], "htp:", ["test=", "plot=", "args=", "debug", "server"])
except getopt.GetoptError: except getopt.GetoptError:
print(usage) print(usage)
...@@ -90,6 +96,9 @@ for opt, arg in opts: ...@@ -90,6 +96,9 @@ for opt, arg in opts:
elif opt in ("--debug"): elif opt in ("--debug"):
debug = True debug = True
elif opt in ("--server"):
run4server = True
# SECTION: TESTS ------------------------------------------------------ # SECTION: TESTS ------------------------------------------------------
if run4Test: if run4Test:
...@@ -137,6 +146,15 @@ elif run4Plot: ...@@ -137,6 +146,15 @@ elif run4Plot:
# print(INFO+"To start interactively:") # print(INFO+"To start interactively:")
# print(SPCE+">> from mfdPlot import * \n") # print(SPCE+">> from mfdPlot import * \n")
elif run4server:
from . import Server
from . import readStupidData
server = Server()
server.init()
server.run()
else: else:
print(usage) print(usage)
......
...@@ -37,7 +37,7 @@ rcParams['font.size'] = '22' ...@@ -37,7 +37,7 @@ rcParams['font.size'] = '22'
try: try:
rcParams['text.usetex'] = True # need dvipng, ghostscript, and Agg rcParams['text.usetex'] = True # need dvipng, ghostscript, and Agg
except: except:
print(WARN + "I couls not set the LaTeX font sorry...") print(WARN + "I could not set the LaTeX font sorry...")
# LINES # LINES
rcParams['lines.linewidth'] = 1.5 rcParams['lines.linewidth'] = 1.5
......
from .myData import MyData
# TECHNICAL ------------------------------------------------------------
D_VERSION='v5'
D_HIERARCHY='SERVER'
D_HOST='localhost'
D_PORT=50803
# FORM -----------------------------------------------------------------
INFO = " > info-: "
WARN = " > warn-: "
SEVR = " > sevr-: "
DBUG = " > dbug-: "
SPCE = " > -----: "
# CONFIGURATION --------------------------------------------------------
# myFig
D_FIGNUM = 0 # default figure number
D_FIGSIZE = (8., 6.) # default figure size
D_REFORMAT = True # default reformat value
D_FORMATTED = False # default formatted value
D_RAWDATA = MyData() # default raw data
D_INPUTARG = 'current' # default Input argument
# myIOs
D_IPATH = '../' # default path to project
# print2file
D_OPATH = 'myplotlib/img/' # default path to ouput
D_OFORMAT = 'png' # default format for ouput
# Debug
D_DEBUG = True # default debug value
from . import socket, AF_INET, SOCK_STREAM
from . import INFO, DBUG, WARN, SEVR, SPCE
SIZE_STATUS_MAX = 1024
from . import ProgressBar
from . import D_DEBUG
DEBUG = D_DEBUG
# CLASS CLIENT ---------------------------------------------------------
class MplClient(object):
# CONSTRUCTOR ------------------------------------------------------
def __init__(self, ip, port):
'''This is a myplotlib client.
It sends instructions to a MplSever at host:port.
'''
self.ip = ip
self.port = port
# just a list of names
#~ self.currentRemoteData = []
# PACK SIGNAL ------------------------------------------------------
def packSignal(self, unpackedSignal):
'''Pack the signal.'''
packedSignal = ''
header, instrucSize = unpackedSignal
header = str(header)
instrucSize = str(instrucSize)
packedSignal = "("+"\""+header+"\""+", "+instrucSize+")"
return(packedSignal)
# PACK INSTRUCTION -------------------------------------------------
def packInstructions(self, instructions):
'''Pack the instructions, a tuple of strings: (header, content).'''
header, packedContent = instructions
packedInstructions = "(\""+header+"\", "+str(packedContent)+")"
return(packedInstructions)
# PACK READDATA CONTENT --------------------------------------------
def packReadDataContent(self, ioFunction, dataName, *args, **kwargs):
'''Pack the content of the instructions for readData.'''
packedContent = "['"+str(dataName)+"', '"+ioFunction.__name__+"', "+str(args)+", "+str(kwargs)+"]"
return(packedContent)
# READ DATA --------------------------------------------------------
def readData(self, ioFunction, dataName, *args, **kwargs):
'''Start the readData procedure.
1. Send ReadData Signal with length of packedInstructions
2. Wait for receipt
3. Send Instructions
4. Wait for status
'''
# Pack instructions and get size
content = self.packReadDataContent(ioFunction, dataName, *args, **kwargs)
packedInstructions = self.packInstructions(('readData', content))
instructionSize = len(packedInstructions)
# Send the signal with size
signal = self.packSignal(('readData', instructionSize))
sock = self.sendSignal(signal)
if(DEBUG):
print(INFO+'Sent Signal, waiting for receipt...')
status = self.waitForReceipt(sock)
# Check status
if not status:
return(False)
if(DEBUG):
print(INFO+'Received the receipt')
print(INFO+'Sent the instructions, waiting for status: ')
# Send Instructions
self.sendInstructions(sock, packedInstructions)
# Check status
status = self.waitForStatus(sock)
if not status:
return(False)
return(True)
# SEND SIGNAL ------------------------------------------------------
def sendSignal(self, packedSignal):
'''Send a signal: readData, newSyncFigure, syncFigFormatRawData'''
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((self.ip, self.port))
sock.sendall(str(packedSignal))
return(sock)
# WAIT FOR RECEIPT -------------------------------------------------
def waitForReceipt(self, sock):
'''Wait for the receipt. return a tuple.'''
answer = sock.recv(SIZE_STATUS_MAX)
status = False
errmsg = ''
header = ''
try:
header, status, errmsg = eval(answer)
except:
print(SEVR+'could not Exctract the receipt.')
print(SEVR+'Received: '+str(answer))
status = eval(status)
if not status:
print(SEVR+"SERVER: "+str(errmsg))
return(status)
# SEND INSTRUCTIONS ------------------------------------------------
def sendInstructions(self, sock, packedInstructions):
'''Send Instructions.'''
sock.sendall(packedInstructions)
return(True)
# SEND ALT INSTRUCTIONS --------------------------------------------
# def sendInstructions(self, packedInstructions):
# '''Send Instructions.'''
# sock = socket(AF_INET, SOCK_STREAM)
# sock.connect((self.ip, self.port))
# sock.sendall(packedInstructions)
#
# return(sock)
# WAIT FOR STATUS --------------------------------------------------
def waitForStatus(self, sock):
'''Wait for the status. return a tuple.'''
answer = sock.recv(SIZE_STATUS_MAX)
status = False
errmsg = ''
header = ''
try:
header, status, errmsg = eval(answer)
except:
print(SEVR+'could not Exctract the status.')
status = eval(status)
if not status:
print(SEVR+"SERVER: "+str(errmsg))
return(status)
# NEW SYNC FIGURE --------------------------------------------------
def newSyncFigure(self, figClass, symbolicRawdata, **kwargs):
'''Start the readData procedure.
1. Send newSyncFigure Signal with length of packedInstructions
2. Wait for receipt
3. Send Instructions
4. Wait for status
'''
# create temporary syncFigure
syncFigure = figClass(symbolicRawdata, **kwargs)
# Pack instructions and get size
content = self.packNewSyncFigureContent(figClass, symbolicRawdata, **kwargs)
packedInstructions = self.packInstructions(('newSyncFigure', content))
instructionSize = len(packedInstructions)
# Send the signal with size
signal = self.packSignal(('newSyncFigure', instructionSize))
sock = self.sendSignal(signal)
if(DEBUG):
print(INFO+'Sent Signal, waiting for receipt...')
# Wait for the receipt
status = self.waitForReceipt(sock)
# Check status
if not status:
del(syncFigure)
return(None)
if(DEBUG):
print(INFO+'Received the receipt')
print(INFO+'Sent the instructions, waiting for status: ')
# Send Instructions
self.sendInstructions(sock, packedInstructions)
# Check status
ID = self.waitForStatus(sock)
# If failed
if not ID:
del(syncFigure)
return(None)
# If created
else:
# Link the temporary Sync Figure
syncFigure.syncID = ID
syncFigure.client = self
return(syncFigure)
# PACK NEW SYNC FIGURE CONTENT -------------------------------------
def packNewSyncFigureContent(self, FigClass, rawdata, **kwargs):
'''Pack the content of the instructions for new Sync Figure.'''
packedContent = "['"+FigClass.__name__+"', "+str(rawdata)+", "+str(kwargs)+"]"
return(packedContent)
# SYNC FIGURE FORMAT RAWDATA ---------------------------------------
def syncFigFormatRawData(self, syncID):
'''the returned datas should be a tuple of strings'''
# Send the signal with syncID
signal = self.packSignal(('syncFigFormatRawData', "'"+syncID+"'"))
sock = self.sendSignal(signal)
if(DEBUG):
print(INFO+'Sent Signal, waiting for the size of the formatted data...')
# Wait for the size of the formatted data
dataSize = self.waitForStatus(sock)
# if failed
if not dataSize:
self.sendCloseConnection(sock)
return(None)
# Send a receipt
self.sendReceipt(sock)
print('CLIENT: I received a data size of: '+str(dataSize))
# Wait for the formatted data
packedData = self.waitForData(sock, dataSize)
# print(INFO+str(packedData))
# Unpack
header, datas, errmsg = self.unpackFormattedData(packedData)
# Check status
if datas is not None:
if(DEBUG):
print(INFO+'Received the data')
else:
print(WARN + 'The server could not format the rawdata.')
print(errmsg)
datas = (None,)
return(datas)
# SEND CLOSE CONNECTION --------------------------------------------
def sendCloseConnection(self, sock):
'''Send a close connection receipt to the server.'''
packedReceipt = self.packAnswer(('', "'False'", 'Close connection'))
sock.sendall(packedReceipt)
return(True)
# SEND RECEIPT -----------------------------------------------------
def sendReceipt(self, sock):
'''Send a receipt to the server.'''
packedReceipt = self.packAnswer(('', "'True'", 'Receipt'))
sock.sendall(packedReceipt)