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 @@
#
# IMPORT ---------------------------------------------------------------
from .config import INFO, WARN, SEVR, DBUG, SPCE
from .config import D_HIERARCHY
import os as os
import numpy as np
np.set_printoptions(threshold='nan')
# Test mpl version:
from matplotlib import __version__ as mplvers
from signal import Signal, Query, Status, Answer
from mpl_unpickler import MplUnpickler
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')
# matplotlib import for client/local -----------------------------------
if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
# matplotlib
from matplotlib.pyplot import figure
from matplotlib.pyplot import rc
from matplotlib.pyplot import show, draw, ion, ioff, clf
from matplotlib.pyplot import close as mpclose
from matplotlib.pyplot import fignum_exists, savefig
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib import is_interactive
#from matplotlib import rcParams
from matplotlib import use
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')
# matplotlib
from matplotlib.pyplot import figure
from matplotlib.pyplot import rc
from matplotlib.pyplot import show, draw, ion, ioff, clf
from matplotlib.pyplot import close as mpclose
from matplotlib.pyplot import fignum_exists, savefig
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib import is_interactive
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
from .myData import MyData
# GLOBAL VARIABLE ------------------------------------------------------
G_RAWDATAS = {'current': MyData()} # raw data Object
_G_WINDOWS = []
# CONFIGURATION --------------------------------------------------------
from .config import D_FIGNUM, D_FIGSIZE, D_REFORMAT, D_FORMATTED
from .config import D_RAWDATA, D_INPUTARG
from .config import D_IPATH
from .config import D_OPATH, D_OFORMAT
from .config import D_DEBUG
from .config import rcParams
# FUNCTIONS ------------------------------------------------------------
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes import MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig import MyFig
# MyFig: Overlay on matplotlib.FigureManager class
if rcParams['backend'] == u'TkAgg':
from .myWin_TkAgg import MyWin_TkAgg as MyWin
elif rcParams['backend'] == u'GTKAgg':
from .myWin_GTKAgg import MyWin_GTKAgg as MyWin
elif rcParams['backend'] == u'WXAgg':
from .myWin_WXAgg import MyWin_WXAgg as MyWin
elif rcParams['backend'] == u'Qt4Agg':
from .myWin_Qt4Agg import MyWin_Qt4Agg as MyWin
elif rcParams['backend'] == u'MacOSX':
from .myWin_MacOSx import MyWin_MacOSx as MyWin
if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
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
# from .test import FigTestServer
# from .test import FigTest
# for testing purpose
# 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 backend you choosed is not supported interactive mode not available")
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
elif rcParams['backend'] == u'GTKAgg':
from .myWin_GTKAgg import MyWin_GTKAgg as MyWin
elif rcParams['backend'] == u'WXAgg':
from .myWin_WXAgg import MyWin_WXAgg as MyWin
elif rcParams['backend'] == u'Qt4Agg':
from .myWin_Qt4Agg import MyWin_Qt4Agg as MyWin
elif rcParams['backend'] == u'MacOSX':
from .myWin_MacOSx import MyWin_MacOSx as MyWin
else:
print(SEVR + "The backend you choosed is not supported interactive mode not available")
# myTool.*: interface functions to use myplotlib interactively
from .mytool import window_exists, getCurrentWindowIDs
from .mytool import print2file, print2screen, printListCurrentWindows
from .mytool import getWindow, getFigOnWindow, drawFigOnWindow, giveDataToWindow
from .mytool import closeWindow, closeAllWindows
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
#if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
# 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 @@
#
#
# IMPORT ---------------------------------------------------------------
from . import D_HIERARCHY
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 getopt
......@@ -56,7 +62,7 @@ usage = '''
# GET OPT
try:
opts, args = getopt.getopt(
sys.argv[1:], "htp:", ["test=", "plot=", "args=", "debug"])
sys.argv[1:], "htp:", ["test=", "plot=", "args=", "debug", "server"])
except getopt.GetoptError:
print(usage)
......@@ -90,6 +96,9 @@ for opt, arg in opts:
elif opt in ("--debug"):
debug = True
elif opt in ("--server"):
run4server = True
# SECTION: TESTS ------------------------------------------------------
if run4Test:
......@@ -137,6 +146,15 @@ elif run4Plot:
# print(INFO+"To start interactively:")
# print(SPCE+">> from mfdPlot import * \n")
elif run4server:
from . import Server
from . import readStupidData
server = Server()
server.init()
server.run()
else:
print(usage)
......
......@@ -37,7 +37,7 @@ rcParams['font.size'] = '22'
try:
rcParams['text.usetex'] = True # need dvipng, ghostscript, and Agg
except:
print(WARN + "I couls not set the LaTeX font sorry...")
print(WARN + "I could not set the LaTeX font sorry...")
# LINES
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)
return(True)
# PACK ANSWER ------------------------------------------------------
def packAnswer(self, answer):
'''Pack an answer, a tuple of strings: (header, content, errmsg).'''
header, packedContent, errmsg = answer
packedAnswer = "(\""+header+"\", "+str(packedContent)+", \""+str(errmsg)+"\")"
return(packedAnswer)
# WAIT FOR DATA ----------------------------------------------------
def waitForData(self, sock, dataSize):
'''Wait for data of size dataSize.'''
receivedSize = 0
unpackedData = b''
progress = ProgressBar(dataSize, fmt=ProgressBar.FULL)
while receivedSize < dataSize:
unpackedData += sock.recv(4096)
progress(4096)
receivedSize = len(unpackedData)
progress.done()
return(unpackedData)
# UNPACKING --------------------------------------------------------
def unpackFormattedData(self, packedData):
'''The packedData should be the string representation
of a tuple of 3 strings.
"(signalID, content, errmsg)"