What I try to do:
I want to write a Python program running on an RPI which communicates to a software called QLab4 via OSC. It should display the received workspace data (JSON format) in a table, while the user is able to select a cue from the table and fire it using a key press.
So far I got two scripts (just proof of concept stage), but I struggle to combine them into one program. Any hints to how to do it would be greatly appreciated.
Script 1:
Starts OSC client & server and sends and receives OSC to/from QLAB.
At the moment it just prints out the JSON (workspace) and the selected cue.
import argparse
import time
import threading
import json
from pythonosc import udp_client
from pythonosc import dispatcher
from pythonosc import osc_server
workspace = {}
def print_json(unused_addr, args):
global workspace
workspace = json.loads(args)
print(workspace)
def print_name(unused_addr, args):
decoded_json = json.loads(args)
print(args)
print(type(decoded_json['data']))
data = decoded_json['data']
print("Cue Name: " + data['displayName'])
print("Cue Number: " + data['number'])
def print_payload(unused_addr, args):
print ("Selected Cue: " + args)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--serverip", default="127.0.0.1", help="The ip to listen on")
parser.add_argument("--serverport", type=int, default=53001, help="The port the OSC Server is listening on")
parser.add_argument("--clientip", default="127.0.0.1", help="The ip of the OSC server")
parser.add_argument("--clientport", type=int, default=53000, help="The port the OSC Client is listening on")
args = parser.parse_args()
# listen to addresses and print changes in values
dispatcher = dispatcher.Dispatcher()
dispatcher.map("/reply/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/cueLists",print_json)
dispatcher.map("/update/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/cueList/*/playbackPosition",print_payload)
dispatcher.map("/reply/cue_id/*/valuesForKeys", print_json)
dispatcher.map("/reply/cue_id/*/valuesForKeys", print_name)
def start_server(ip, port):
print("Starting Server")
server = osc_server.ThreadingOSCUDPServer(
(ip, port), dispatcher)
print("Serving on {}".format(server.server_address))
thread = threading.Thread(target=server.serve_forever)
thread.start()
def start_client(ip, port):
print("Starting Client")
client = udp_client.SimpleUDPClient(ip, port)
# print("Sending on {}".format(client.))
thread = threading.Thread(target=get_workspace(client))
thread2 = threading.Thread(target=print_active(client))
thread.start()
thread2.start()
# send random values between 0-1 to the three addresses
def get_workspace(client):
client.send_message("/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/cueLists", 1)
client.send_message("/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/updates", 1)
def print_active(client):
while True:
client.send_message("/cue/active/valuesForKeys", "[\"displayName\",\"number\", \"type\", \"isBroken\", "
"\"isLoaded\", \"isPaused\", \"isRunning\", \"preWait\", \"duration\", \"postWait\"]")
time.sleep(1)
start_server(args.serverip, 53001)
start_client(args.clientip, 53000)
Script 2:
I copied the received JSON string of the workspace as variable. Then it builds a table using pyQt5. After hitting "R" it inserts a row for each received cue.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import json
# var
cue_count = 1
cue_id = ""
# data
data = '{"status":"ok","data":[{"number":"","uniqueID":"0CBC2F3A-B4CB-46A0-AE74-0810598256AD","cues":' \
'[{"number":"1","uniqueID":"C358F03C-128B-4BBA-B8D8-3E1C3D217775","flagged":false,' \
'"listName":"Cue 1","type":"Memo","colorName":"none","name":"Cue 1","armed":true},' \
'{"number":"2","uniqueID":"F2FDC19F-8E4F-43E6-B49F-BA421C886E63","flagged":false,' \
'"listName":"Cue 2","type":"Memo","colorName":"none","name":"Cue 2","armed":true},' \
'{"number":"3","uniqueID":"244B2654-51B3-4423-AF1A-6894F301CA6B","flagged":false,' \
'"listName":"Cue 3","type":"Memo","colorName":"none","name":"Cue 3","armed":true},' \
'{"number":"4","uniqueID":"42B37827-A5E8-444D-82D1-7706A8E197A6","flagged":false,' \
'"listName":"Cue 4","type":"Memo","colorName":"none","name":"Cue 4","armed":true}],' \
'"flagged":false,"listName":"Main Cue List","type":"Cue List","colorName":"none",' \
'"name":"Main Cue List","armed":true}],"workspace_id":"C936DAAF-D5C7-4D1D-8382-54CA426A1BDC",' \
'"address":"\/workspace\/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC\/cueLists"}'
class TableFromList(QTableWidget):
def __init__(self, data, *args):
# Call parent constructor
QTableWidget.__init__(self, *args)
# Set the necessary configurations fot the table
self.data = data
self.resizeColumnsToContents()
self.resizeRowsToContents()
self.setColumnWidth(0, 100)
self.setColumnWidth(0, 40)
self.setColumnWidth(1, 200)
self.setColumnWidth(2, 80)
self.setColumnWidth(3, 80)
self.setMinimumWidth(400)
self.setWindowTitle("WORKSPACE")
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.setStyleSheet("color:white; background-color:black; font-weight: bold; selection-background-color: orange")
self.setFont(QFont('Arial', 14))
# Declare the variable to set the header content
headers = ["No.", "NAME", "Armed"]
# Set the header label of the table
self.setHorizontalHeaderLabels(headers)
# Read the particular cell value
self.clicked.connect(self.on_click)
self.currentItemChanged.connect(self.select_cue)
# Display the window in the center of the screen
win = self.frameGeometry()
pos = QDesktopWidget().availableGeometry().center()
win.moveCenter(pos)
self.move(win.topLeft())
self.show()
def on_click(self):
for ItemVal in self.selectedItems():
# Read the header value based on the selected cell
subject = self.horizontalHeaderItem(ItemVal.column()).text()
# Print the detail information of the mark
print("\n", self.ID_list[ItemVal.row()], " got ", ItemVal.text(), " in ", subject)
def select_cue(self):
global cue_id
global data
data_dict = json.loads(data)
data_parsed = data_dict["data"][0]["cues"]
value = self.currentRow()
cue = self.item(value, 0)
cue_number = cue.text()
cue_number = int(cue_number) - 1
cue_id = data_parsed[cue_number]["uniqueID"]
print("ID: " + cue_id)
print("Cue Number is: " + cue.text())
def keyPressEvent(self, keyEvent):
super(TableFromList, self).keyPressEvent(keyEvent)
data = self.data
def build_cuelist(data):
data_dict = json.loads(data)
cue_count = len(data_dict["data"][0]["cues"])
data = data_dict["data"][0]["cues"]
self.setRowCount(0)
for i in range(cue_count):
rowPosition = table.rowCount()
table.insertRow(rowPosition) # insert new row
self.setItem(rowPosition, 0, QTableWidgetItem(str(data[i]["number"])))
self.setItem(rowPosition, 1, QTableWidgetItem(str(data[i]["name"])))
self.setItem(rowPosition, 2, QTableWidgetItem(str(data[i]["armed"])))
if keyEvent.key() == Qt.Key_Return:
print('*** Return pressed')
print("OSC: /cue/" + cue_id + "/go")
elif keyEvent.key() == Qt.Key_Enter:
print('*** Enter pressed')
elif keyEvent.key() == Qt.Key_1:
print('*** 1 pressed')
elif keyEvent.key() == Qt.Key_R:
build_cuelist(self.data)
# Create app object and execute the app
app = QApplication(sys.argv)
table = TableFromList(data, 0, 3)
table.show()
app.exec()
The code provided by the OP has various errors such as threads not being executed in a second thread, the code works because threads are not needed.
On the other hand, signals must be used to send the information from the callbacks to the widgets.
import json
import sys
import threading
from dataclasses import dataclass
from functools import cached_property
from PyQt5 import QtCore, QtGui, QtWidgets
from pythonosc import dispatcher
from pythonosc import osc_server
from pythonosc import udp_client
#dataclass
class Server(QtCore.QObject):
ip: str = "127.0.0.1"
port: int = 53001
datachanged = QtCore.pyqtSignal(dict)
def __post_init__(self):
super().__init__()
#cached_property
def osc_server(self):
dp = dispatcher.Dispatcher()
dp.map(
"/reply/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/cueLists",
self.handle_reply_workspace,
)
dp.map(
"/update/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/cueList/*/playbackPosition",
self.handle_update_workspace,
)
dp.map(
"/cue/active/valuesForKeys",
self.handle_cue_id,
)
return osc_server.ThreadingOSCUDPServer((self.ip, self.port), dp)
def start(self):
threading.Thread(target=self.osc_server.serve_forever, daemon=True).start()
def handle_reply_workspace(self, unused_addr, data):
try:
d = json.loads(data)
except json.JSONDecodeError as e:
print(str(e))
else:
self.datachanged.emit(d)
def handle_update_workspace(self, unused_addr, data):
print(data)
def handle_cue_id(self, unused_addr, data):
print(data)
#dataclass
class Client(QtCore.QObject):
ip: str = "127.0.0.1"
port: int = 53000
datachanged = QtCore.pyqtSignal(dict)
def __post_init__(self):
super().__init__()
def start_timer(self, dt=1000):
self.timer.start(dt)
def request_workspace(self):
self.osc_client.send_message(
"/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/cueLists", 1
)
self.osc_client.send_message(
"/workspace/C936DAAF-D5C7-4D1D-8382-54CA426A1BDC/updates", 1
)
#cached_property
def osc_client(self):
return udp_client.SimpleUDPClient(self.ip, self.port)
#cached_property
def timer(self):
timer = QtCore.QTimer()
timer.timeout.connect(self.handle_timeout)
return timer
#QtCore.pyqtSlot()
def handle_timeout(self):
keys = [
"displayName",
"number",
"type",
"isBroken",
"isLoaded",
"isPaused",
"isRunning",
"preWait",
"duration",
"postWait",
]
self.osc_client.send_message(
"/cue/active/valuesForKeys",
json.dumps(keys),
)
class TableWidget(QtWidgets.QTableWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setColumnCount(3)
self.setHorizontalHeaderLabels(["No.", "NAME", "Armed"])
self.setWindowTitle("WORKSPACE")
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.setStyleSheet(
"""
color:white;
background-color:black;
font-weight: bold;
selection-background-color: orange
"""
)
self.setFont(QtGui.QFont("Arial", 14))
self.setColumnWidth(0, 40)
self.setColumnWidth(1, 200)
self.setColumnWidth(2, 80)
self.setMinimumWidth(400)
#QtCore.pyqtSlot(dict)
def update_data(self, data):
self.setRowCount(0)
keys = ("number", "name", "armed")
cues = data["data"][0]["cues"]
for i, cue in enumerate(cues):
self.insertRow(self.rowCount())
for j, key in enumerate(keys):
value = cue[key]
item = QtWidgets.QTableWidgetItem()
item.setData(QtCore.Qt.DisplayRole, value)
self.setItem(i, j, item)
def main():
app = QtWidgets.QApplication(sys.argv)
server = Server()
server.start()
client = Client()
client.request_workspace()
client.start_timer()
table_widget = TableWidget()
table_widget.resize(640, 480)
table_widget.show()
server.datachanged.connect(table_widget.update_data)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Related
I need to process a very large number of traps (10,000 per second). I have the simplest linux server. I tried to implement through threads, but cpu clogs up very quickly. Please tell me how to minimize the load on memory and processor, but at the same time process a large number of traps?
There is also work with the database. Writing to the database of taps
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity.rfc3413 import ntfrcv
import psycopg2
from pysnmp.hlapi import SnmpEngine as Sm, CommunityData, UdpTransportTarget,\
ContextData, ObjectType, ObjectIdentity, getCmd
from datetime import datetime
import logging.config
from os import getpid, system, stat, path, chdir, listdir, remove
from threading import Thread
snmpEngine = engine.SnmpEngine()
config.addTransport(
snmpEngine,
udp.domainName + (1,),
udp.UdpTransport().openServerMode(('localhost', 162))
)
config.addV1System(snmpEngine, '', 'public')
class cbFun(Thread):
def __init__(self, snmpEngine, stateReference, contextEngineId, contextName,
varBinds, cbCtx):
Thread.__init__(self)
self.snmpEngine = snmpEngine
self.stateReference = stateReference
self.contextEngineId = contextEngineId
self.contextName = contextName
self.varBinds = varBinds
self.cbCtx = cbCtx
self.localConnected = False
self.localDb = None
self.errorFlag = False
self.start()
def run(self):
print('\n{0}New trap message received on {1} {0}'.format(
'-' * 7,
datetime.now().strftime('%d-%b-%Y at %H:%M:%S')))
execContext = self.snmpEngine.observer.getExecutionContext(
'rfc3412.receiveMessage:request')
print('Trap is coming from %s:%s' % execContext['transportAddress'])
dict_traps = {}
for name, val in self.varBinds:
oid = name.prettyPrint()
value = val.prettyPrint()
print(f'{oid} = {value}')
dict_traps.update({oid: value})
connectDB(dict_traps)
def connectDB(self, values):
connect = psycopg2.connect(dbname="test", user="test",
password="test",
host="test")
cursor = connect.cursor()
for key,value in values:
command = f"insert into TRAPS VALUES ({key}, {value})"
cursor.execute(command)
connect.commit()
connect.close()
ntfrcv.NotificationReceiver(snmpEngine, cbFun)
snmpEngine.transportDispatcher.jobStarted(1)
try:
snmpEngine.transportDispatcher.runDispatcher()
except:
snmpEngine.transportDispatcher.closeDispatcher()
raise
I want to insert the QLineEdit input into a database
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from PyQt5 import QtSql as qsql
class Secondwindow(qtw.QWidget):
'''
description einfügen
'''
# Attribut Signal
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# your code will go here
# Messung starten
self.connectdb_button = qtw.QPushButton("Connect to Database ?")
hlaout_layout = qtw.QHBoxLayout()
hlaout_layout.addStretch(1)
hlaout_layout.addWidget(self.connectdb_button)
hlaout_layout.addStretch(1)
# input /nested layout
input1_label = qtw.QLabel("input 1 ")
self.input_1 = qtw.QLineEdit()
input1_hlayout = qtw.QHBoxLayout()
input1_hlayout.addStretch(1)
input1_hlayout.addWidget(input1_label)
input1_hlayout.addWidget(self.input_1)
input1_hlayout.addStretch(1)
input1_hlayout.setAlignment(qtc.Qt.AlignHCenter)
input2_label = qtw.QLabel("input 2 ")
self.input_2 = qtw.QLineEdit()
input2_hlayout = qtw.QHBoxLayout()
input2_hlayout.addStretch(1)
input2_hlayout.addWidget(input2_label)
input2_hlayout.addWidget(self.input_2)
input2_hlayout.addStretch(1)
input2_hlayout.setAlignment(qtc.Qt.AlignHCenter)
input3_label = qtw.QLabel("input 3 ")
self.input_3 = qtw.QLineEdit()
input3_hlayout = qtw.QHBoxLayout()
input3_hlayout.addStretch(1)
input3_hlayout.addWidget(input3_label)
input3_hlayout.addWidget(self.input_3)
input3_hlayout.addStretch(1)
input3_hlayout.setAlignment(qtc.Qt.AlignHCenter)
input4_label = qtw.QLabel("input 4 ")
self.input_4 = qtw.QLineEdit()
input4_hlayout = qtw.QHBoxLayout()
input4_hlayout.addStretch(1)
input4_hlayout.addWidget(input4_label)
input4_hlayout.addWidget(self.input_4)
input4_hlayout.addStretch(1)
input4_hlayout.setAlignment(qtc.Qt.AlignHCenter)
input5_label = qtw.QLabel("input 5 ")
self.input_5 = qtw.QLineEdit()
input5_hlayout = qtw.QHBoxLayout()
input5_hlayout.addStretch(1)
input5_hlayout.addWidget(input5_label)
input5_hlayout.addWidget(self.input_5)
input5_hlayout.addStretch(1)
input5_hlayout.setAlignment(qtc.Qt.AlignHCenter)
# select button
self.select_button = qtw.QPushButton("start query ")
select_buttonlayout = qtw.QHBoxLayout()
select_buttonlayout.setAlignment(qtc.Qt.AlignHCenter)
select_buttonlayout.addStretch(1)
select_buttonlayout.addWidget(self.select_button)
select_buttonlayout.addStretch(1)
# hauptlayout
haupt_layout = qtw.QFormLayout()
haupt_layout.addRow(self.connectdb_button)
haupt_layout.setVerticalSpacing(20)
haupt_layout.addRow(input1_hlayout)
haupt_layout.setVerticalSpacing(20)
haupt_layout.addRow(input2_hlayout)
haupt_layout.setVerticalSpacing(20)
haupt_layout.addRow(input3_hlayout)
haupt_layout.setVerticalSpacing(20)
haupt_layout.addRow(input4_hlayout)
haupt_layout.setVerticalSpacing(20)
haupt_layout.addRow(input5_hlayout)
haupt_layout.setVerticalSpacing(30)
haupt_layout.addRow(select_buttonlayout)
self.setLayout(haupt_layout)
self.show()
# Funktionalität
self.connectdb_button.clicked.connect(self.connect_to_db)
self.select_button.clicked.connect(self.query_data)
def connect_to_db(self):
self.database = qsql.QSqlDatabase.addDatabase('QSQLITE')
self.database.setDatabaseName('qtdatabase.db')
self.database.open()
if self.database.isOpen():
qtw.QMessageBox.about(self, 'connectet', "connection to db successful")
# einfügen siehe pdf
# if not self.db.open():
# error = self.db.lastError().text()
# qtw.QMessageBox.critical(
# None, 'DB Connection Error',
# 'Could not open database file: '
# f'{error}')
# sys.exit(1)
def query_data(self):
mein_input = []
item1 = self.input_1.text()
item2 = self.input_2.text()
item3 = self.input_3.text()
item4 = self.input_4.text()
item5 = self.input_5.text()
mein_input.append(item1)
mein_input.append(item2)
mein_input.append(item3)
mein_input.append(item4)
mein_input.append(item5)
self.query = qsql.QSqlQuery()
self.query.prepare("INSERT INTO userinput(firstcolumns) VALUES(?)")
self.query.addBindValue(mein_input)
if not self.query.execBatch():
print(self.query.lastError().text())
self.close()
# if not self.database.isOpen():
# qtw.QMessageBox.about(self, 'Erfolg', "Data inserted successfully")
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
w = Secondwindow()
sys.exit(app.exec_())
I get this error
Parameter count mismatch
When I insert a list instead of the LineEdit input the function works fine.
I checked that the table exists in the database also the column
output: ['firstcolumns']
import sqlite3
# connect to database query starten
try:
db_connection = sqlite3.connect("qtdatabase.db")
cursor = db_connection.cursor()
column_abfrage = '''SELECT * FROM userinput;'''
cursor.execute(column_abfrage)
cursor.close()
names = list(map(lambda x: x[0], cursor.description))
print(names)
except sqlite3.Error as error:
print(error)
finally:
if (db_connection):
db_connection.close()
print("db connection closed")
sqlite is a database that has a particular characteristic: If the database does not exist when you try to open then it will be created so the open() method will always return True so it can generate silent problems.
In this case it is always advisable to use the full path, this can be explicitly: "/full/path/of/database" or built based on the location of the script, for example if the database is in the same script folder then you can use the following code:
import os
# ...
current_dir = os.path.dirname(os.path.realpath(__file__))
db_path = os.path.join(current_dir, "qtdatabase.db")
self.database = qsql.QSqlDatabase.addDatabase('QSQLITE')
self.database.setDatabaseName(db_path)
if self.database.open():
qtw.QMessageBox.about(self, 'connectet', "connection to db successful")
In your case you are probably using some IDE that when running the script uses a working directory different from the location of the script.
I've written some api to communicate with a website using websocketapp. It works fine only on 2 pc. If i put my code on every other pc the websocket doesnt receive any message and closes. I've tried a lot of different machines and operating systems, many version of python (included the same that works), wireless and wired connection but nothing changed. There's no error or exception. What can it be?
EDIT: i don't own the website or the server. All other methods send messages and parse the response in on_socket_message
import requests
import websocket
import time
from threading import Thread
from datetime import datetime
import json
from position import Position
from constants import ACTIVES
class IQOption():
practice_balance = 0
real_balance = 0
server_time = 0
positions = {}
instruments_categories = ["cfd","forex","crypto"]
top_assets_categories = ["forex","crypto","fx-option"]
instruments_to_id = ACTIVES
id_to_instruments = {y:x for x,y in ACTIVES.items()}
market_data = {}
binary_expiration_list = {}
open_markets = {}
digital_strike_list = {}
candle_data = []
latest_candle = 0
position_id = 0
quotes =[]
position_id_list=[]
def __init__(self,username,password,host="iqoption.com"):
self.username = username
self.password = password
self.host = host
self.session = requests.Session()
self.generate_urls()
self.socket = websocket.WebSocketApp(self.socket_url,on_open=self.on_socket_connect,on_message=self.on_socket_message,on_close=self.on_socket_close,on_error=self.on_socket_error)
def generate_urls(self):
"""Generates Required Urls to operate the API"""
#https://auth.iqoption.com/api/v1.0/login
self.api_url = "https://{}/api/".format(self.host)
self.socket_url = "wss://{}/echo/websocket".format(self.host)
self.login_url = self.api_url+"v1.0/login"
self.profile_url = self.api_url+"profile"
self.change_account_url = self.profile_url+"/"+"changebalance"
self.getprofile_url = self.api_url+"getprofile"
def login(self):
"""Login and set Session Cookies"""
print("LOGIN")
data = {"email":self.username,"password":self.password}
self.log_resp = self.session.request(url="https://auth.iqoption.com/api/v1.0/login",data=data,method="POST")
requests.utils.add_dict_to_cookiejar(self.session.cookies, dict(platform="9"))
self.__ssid = self.log_resp.cookies.get("ssid")
print(self.__ssid)
self.start_socket_connection()
time.sleep(1) ## artificial delay to complete socket connection
self.log_resp2 = self.session.request(url="https://eu.iqoption.com/api/getprofile",method="GET")
ss = self.log_resp2._content.decode('utf-8')
js_ss=json.loads(ss)
self.parse_account_info(js_ss)
self.balance_id = js_ss["result"]["balance_id"]
self.get_instruments()
self.get_top_assets()
self.setOptions()
#self.getFeatures()
time.sleep(1)
print(js_ss["isSuccessful"])
return js_ss["isSuccessful"]
def on_socket_message(self,socket,message):
#do things
def on_socket_connect(self,socket):
"""Called on Socket Connection"""
self.initial_subscriptions()
print("On connect")
def initial_subscriptions(self):
self.send_socket_message("ssid",self.__ssid)
self.send_socket_message("subscribe","tradersPulse")
def on_socket_error(self,socket,error):
"""Called on Socket Error"""
print(message)
def on_socket_close(self,socket):
"""Called on Socket Close, does nothing"""
def start_socket_connection(self):
"""Start Socket Connection"""
self.socket_thread = Thread(target=self.socket.run_forever)
self.socket_thread.start()
def send_socket_message(self,name,msg):
#print(msg)
data = {"name":name,"msg":msg}
self.socket.send(json.dumps(data))
Here is an example running under Gevent Websockets. This makes it ASYNC (which I suspect is part of your problem) and allows for bidirectional communication.
import gevent
from gevent import monkey, signal, Timeout, sleep, spawn as gspawn
monkey.patch_all()
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
from geventwebsocket import WebSocketError
import bottle
from bottle import get, route, template, request, response, abort, static_file
import ujson as json
#route('/static/<filepath:path>')
def server_static(filepath):
return static_file(filepath, root='static')
#route('/ws/remote')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
while 1:
try:
message = ''
with Timeout(2, False) as timeout:
message = wsock.receive()
if message:
message = json.loads(message)
if 'command' in message:
r.command(message['command'])
except WebSocketError:
break
except Exception as exc:
print(str(exc))
#get('/')
def remote():
return template('templates/remote.tpl', title='WebsocketTest', websocket=WEBSOCKET, command='command', status=status)
if __name__ == '__main__':
r=None
status="Connecting..."
gspawn(initialize)
print 'Started...'
HOST = socket.gethostbyname(socket.gethostname())
HOST = 'localhost'
WEBSOCKET = 'ws://{}/ws/remote'.format(HOST)
botapp = bottle.app()
server = WSGIServer(("0.0.0.0", 80), botapp, handler_class=WebSocketHandler)
def shutdown():
print('Shutting down ...')
server.stop(timeout=60)
exit(signal.SIGTERM)
gevent.signal(signal.SIGTERM, shutdown)
gevent.signal(signal.SIGINT, shutdown) #CTRL C
server.serve_forever()
Then in your HTML you really should use reconnecting websocket library
https://github.com/joewalnes/reconnecting-websocket
<button id="TRIGGERED" type="button" class="btn btn-outline-primary">TRIGGER</button>
<script type="text/javascript" src="/static/reconnecting-websocket.min.js"></script>
<script>
var ws = new ReconnectingWebSocket('{{websocket}}');
ws.reconnectInterval = 3000;
ws.maxReconnectAttempts = 10;
ws.onmessage = function (evt) {
var wsmsg = JSON.parse(evt.data);
console.log(evt.data)
};
$("button").click(function() {
<!--console.log(this.id);-->
ws.send(JSON.stringify({'{{command}}': this.id}));
});
</script>
python call ansibleApi with celery return None,I have searched a few days.It works well with call deploy function without celery ,but with celery my code call ansibleApi return None.
reproduce steps.
1.tasks.py
from celery import shared_task
from .deploy_tomcat2 import django_process
#shared_task
def deploy(jira_num):
#return 'hello world {0}'.format(jira_num)
#rdb.set_trace()
return django_process(jira_num)
2.deploy_tomcat2.py
from .AnsibleApi import CallApi
def django_process(jira_num):
server = '10.10.10.30'
name = 'abc'
port = 11011
code = 'efs'
jdk = '1.12.13'
jvm = 'xxxx'
if str.isdigit(jira_num):
# import pdb
# pdb.set_trace()
call = CallApi(server,name,port,code,jdk,jvm)
return call.run_task()
3.AnsibleApi.py
#!/usr/bin/env python
import logging
from .Logger import Logger
from django.conf import settings
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.inventory import Inventory
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
Log = Logger('/tmp/auto_deploy_tomcat.log',logging.INFO)
class ResultCallback(CallbackBase):
def __init__(self, *args, **kwargs):
super(ResultCallback ,self).__init__(*args, **kwargs)
self.host_ok = {}
self.host_unreachable = {}
self.host_failed = {}
def v2_runner_on_unreachable(self, result):
self.host_unreachable[result._host.get_name()] = result
def v2_runner_on_ok(self, result, *args, **kwargs):
self.host_ok[result._host.get_name()] = result
def v2_runner_on_failed(self, result, *args, **kwargs):
self.host_failed[result._host.get_name()] = result
class CallApi(object):
user = settings.SSH_USER
ssh_private_key_file = settings.SSH_PRIVATE_KEY_FILE
results_callback = ResultCallback()
Options = namedtuple('Options',
['connection', 'module_path', 'private_key_file', 'forks', 'become', 'become_method',
'become_user', 'check'])
def __init__(self,ip,name,port,code,jdk,jvm):
self.ip = ip
self.name = name
self.port = port
self.code = code
self.jdk = jdk
self.jvm = jvm
self.results_callback = ResultCallback()
self.results_raw = {}
def _gen_user_task(self):
tasks = []
deploy_script = 'autodeploy/tomcat_deploy.sh'
dst_script = '/tmp/tomcat_deploy.sh'
cargs = dict(src=deploy_script, dest=dst_script, owner=self.user, group=self.user, mode='0755')
args = "%s %s %d %s %s '%s'" % (dst_script, self.name, self.port, self.code, self.jdk, self.jvm)
tasks.append(dict(action=dict(module='copy', args=cargs),register='shell_out'))
tasks.append(dict(action=dict(module='debug', args=dict(msg='{{shell_out}}'))))
# tasks.append(dict(action=dict(module='command', args=args)))
# tasks.append(dict(action=dict(module='command', args=args), register='result'))
# tasks.append(dict(action=dict(module='debug', args=dict(msg='{{result.stdout}}'))))
self.tasks = tasks
def _set_option(self):
self._gen_user_task()
self.variable_manager = VariableManager()
self.loader = DataLoader()
self.options = self.Options(connection='smart', module_path=None, private_key_file=self.ssh_private_key_file, forks=None,
become=True, become_method='sudo', become_user='root', check=False)
self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=[self.ip])
self.variable_manager.set_inventory(self.inventory)
play_source = dict(
name = "auto deploy tomcat",
hosts = self.ip,
remote_user = self.user,
gather_facts='no',
tasks = self.tasks
)
self.play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
def run_task(self):
self.results_raw = {'success':{}, 'failed':{}, 'unreachable':{}}
tqm = None
from celery.contrib import rdb;rdb.set_trace()
#import pdb;pdb.set_trace()
self._set_option()
try:
tqm = TaskQueueManager(
inventory=self.inventory,
variable_manager=self.variable_manager,
loader=self.loader,
options=self.options,
passwords=None,
stdout_callback=self.results_callback,
)
result = tqm.run(self.play)
finally:
if tqm is not None:
tqm.cleanup()
for host, result in self.results_callback.host_ok.items():
self.results_raw['success'][host] = result._result
for host, result in self.results_callback.host_failed.items():
self.results_raw['failed'][host] = result._result
for host, result in self.results_callback.host_unreachable.items():
self.results_raw['unreachable'][host]= result._result
Log.info("result is :%s" % self.results_raw)
return self.results_raw
4.celery worker
celery -A jira worker -Q queue.ops.deploy -n "deploy.%h" -l info
5.produce msg:
deploy.apply_async(args=['150'], queue='queue.ops.deploy', routing_key='ops.deploy')
It seems OK.
The only question is None is really the deploy task return?
It will be better that if you can post your celery worker log.
there are two method to solve this problem ,disable assert:
1.where celery starts set export PYTHONOPTIMIZE=1 OR start celery with this parameter -O OPTIMIZATION
2.disable python packet multiprocessing process.py line 102:
assert not _current_process._config.get('daemon'), \
'daemonic processes are not allowed to have children'
I'm working on a python web-browser using PyQt4/QtWebKit and I need to enable plugins so it can render flash content.
When I add this line I get a core dump QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, True)
My System
Linux rwilson-Aspire-E5-521 3.16.0-47-generic #63~14.04.1-Ubuntu SMP Fri Aug 14 22:56:59 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
PyQt Version
('Qt version:', '4.8.6')
('SIP version:', '4.15.5')
('PyQt version:', '4.10.4')
Here is all the code
#!/usr/bin/env python
from PyQt4 import QtCore, QtGui, QtNetwork, QtWebKit
from PyQt4.QtWebKit import QWebSettings
QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, True)
try:
import jquery_rc3
except ImportError:
import jquery_rc2
class MainWindow(QtGui.QMainWindow):
def __init__(self, url):
super(MainWindow, self).__init__()
self.progress = 0
fd = QtCore.QFile(":/jquery.min.js")
if fd.open(QtCore.QIODevice.ReadOnly | QtCore.QFile.Text):
self.jQuery = QtCore.QTextStream(fd).readAll()
fd.close()
else:
self.jQuery = ''
QtNetwork.QNetworkProxyFactory.setUseSystemConfiguration(True)
self.view = QtWebKit.QWebView(self)
self.view.load(url)
self.view.loadFinished.connect(self.adjustLocation)
self.view.titleChanged.connect(self.adjustTitle)
self.view.loadProgress.connect(self.setProgress)
self.view.loadFinished.connect(self.finishLoading)
self.locationEdit = QtGui.QLineEdit(self)
self.locationEdit.setSizePolicy(QtGui.QSizePolicy.Expanding,
self.locationEdit.sizePolicy().verticalPolicy())
self.locationEdit.returnPressed.connect(self.changeLocation)
toolBar = self.addToolBar("Navigation")
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Back))
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Forward))
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Reload))
toolBar.addAction(self.view.pageAction(QtWebKit.QWebPage.Stop))
toolBar.addWidget(self.locationEdit)
viewMenu = self.menuBar().addMenu("&View")
viewSourceAction = QtGui.QAction("Page Source", self)
viewSourceAction.triggered.connect(self.viewSource)
viewMenu.addAction(viewSourceAction)
effectMenu = self.menuBar().addMenu("&Effect")
effectMenu.addAction("Highlight all links", self.highlightAllLinks)
self.rotateAction = QtGui.QAction(
self.style().standardIcon(
QtGui.QStyle.SP_FileDialogDetailedView),
"Turn images upside down", self, checkable=True,
toggled=self.rotateImages)
effectMenu.addAction(self.rotateAction)
toolsMenu = self.menuBar().addMenu("&Tools")
toolsMenu.addAction("Remove GIF images", self.removeGifImages)
toolsMenu.addAction("Remove all inline frames",
self.removeInlineFrames)
toolsMenu.addAction("Remove all object elements",
self.removeObjectElements)
toolsMenu.addAction("Remove all embedded elements",
self.removeEmbeddedElements)
self.setCentralWidget(self.view)
self.setUnifiedTitleAndToolBarOnMac(True)
def viewSource(self):
accessManager = self.view.page().networkAccessManager()
request = QtNetwork.QNetworkRequest(self.view.url())
reply = accessManager.get(request)
reply.finished.connect(self.slotSourceDownloaded)
def slotSourceDownloaded(self):
reply = self.sender()
self.textEdit = QtGui.QTextEdit(None)
self.textEdit.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.textEdit.show()
self.textEdit.setPlainText(QtCore.QTextStream(reply).readAll())
self.textEdit.resize(600, 400)
reply.deleteLater()
def adjustLocation(self):
self.locationEdit.setText(self.view.url().toString())
def changeLocation(self):
url = QtCore.QUrl.fromUserInput(self.locationEdit.text())
self.view.load(url)
self.view.setFocus()
def adjustTitle(self):
if 0 < self.progress < 100:
self.setWindowTitle("%s (%s%%)" % (self.view.title(), self.progress))
else:
self.setWindowTitle(self.view.title())
def setProgress(self, p):
self.progress = p
self.adjustTitle()
def finishLoading(self):
self.progress = 100
self.adjustTitle()
self.view.page().mainFrame().evaluateJavaScript(self.jQuery)
self.rotateImages(self.rotateAction.isChecked())
def highlightAllLinks(self):
code = """$('a').each(
function () {
$(this).css('background-color', 'yellow')
}
)"""
self.view.page().mainFrame().evaluateJavaScript(code)
def rotateImages(self, invert):
if invert:
code = """
$('img').each(
function () {
$(this).css('-webkit-transition', '-webkit-transform 2s');
$(this).css('-webkit-transform', 'rotate(180deg)')
}
)"""
else:
code = """
$('img').each(
function () {
$(this).css('-webkit-transition', '-webkit-transform 2s');
$(this).css('-webkit-transform', 'rotate(0deg)')
}
)"""
self.view.page().mainFrame().evaluateJavaScript(code)
def removeGifImages(self):
code = "$('[src*=gif]').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
def removeInlineFrames(self):
code = "$('iframe').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
def removeObjectElements(self):
code = "$('object').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
def removeEmbeddedElements(self):
code = "$('embed').remove()"
self.view.page().mainFrame().evaluateJavaScript(code)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
if len(sys.argv) > 1:
url = QtCore.QUrl(sys.argv[1])
else:
url = QtCore.QUrl('http://www.google.com/ncr')
browser = MainWindow(url)
browser.show()
sys.exit(app.exec_())
You need to have an instance of QApplication before using QWebSettings.
Try moving the offending line to MainWindow.__init__.