From: <ni...@us...> - 2010-11-03 13:18:06
|
Revision: 65 http://openautomation.svn.sourceforge.net/openautomation/?rev=65&view=rev Author: nilss1 Date: 2010-11-03 13:17:57 +0000 (Wed, 03 Nov 2010) Log Message: ----------- sorry, too many updates cleanup later, just want to keep a version in repo Modified Paths: -------------- PyWireGate/trunk/WireGate.py PyWireGate/trunk/connector.py PyWireGate/trunk/datastore.py PyWireGate/trunk/knx_connector/BusMonitor.py PyWireGate/trunk/knx_connector/DPT_Types.py PyWireGate/trunk/knx_connector/GroupSocket.py PyWireGate/trunk/knx_connector/KNX_Connector.py PyWireGate/trunk/owfs_connector/OWFS_Connector.py PyWireGate/trunk/owfs_connector/connection.py Added Paths: ----------- PyWireGate/trunk/DSupdate.py PyWireGate/trunk/simplejson/ PyWireGate/trunk/simplejson/.___init__.py PyWireGate/trunk/simplejson/._decoder.py PyWireGate/trunk/simplejson/._scanner.py PyWireGate/trunk/simplejson/__init__.py PyWireGate/trunk/simplejson/_speedups.c PyWireGate/trunk/simplejson/decoder.py PyWireGate/trunk/simplejson/encoder.py PyWireGate/trunk/simplejson/ordered_dict.py PyWireGate/trunk/simplejson/scanner.py PyWireGate/trunk/simplejson/tests/ PyWireGate/trunk/simplejson/tests/.___init__.py PyWireGate/trunk/simplejson/tests/._test_dump.py PyWireGate/trunk/simplejson/tests/._test_errors.py PyWireGate/trunk/simplejson/tests/._test_fail.py PyWireGate/trunk/simplejson/tests/__init__.py PyWireGate/trunk/simplejson/tests/test_check_circular.py PyWireGate/trunk/simplejson/tests/test_decimal.py PyWireGate/trunk/simplejson/tests/test_decode.py PyWireGate/trunk/simplejson/tests/test_default.py PyWireGate/trunk/simplejson/tests/test_dump.py PyWireGate/trunk/simplejson/tests/test_encode_basestring_ascii.py PyWireGate/trunk/simplejson/tests/test_encode_for_html.py PyWireGate/trunk/simplejson/tests/test_errors.py PyWireGate/trunk/simplejson/tests/test_fail.py PyWireGate/trunk/simplejson/tests/test_float.py PyWireGate/trunk/simplejson/tests/test_indent.py PyWireGate/trunk/simplejson/tests/test_pass1.py PyWireGate/trunk/simplejson/tests/test_pass2.py PyWireGate/trunk/simplejson/tests/test_pass3.py PyWireGate/trunk/simplejson/tests/test_recursion.py PyWireGate/trunk/simplejson/tests/test_scanstring.py PyWireGate/trunk/simplejson/tests/test_separators.py PyWireGate/trunk/simplejson/tests/test_speedups.py PyWireGate/trunk/simplejson/tests/test_unicode.py PyWireGate/trunk/simplejson/tool.py Added: PyWireGate/trunk/DSupdate.py =================================================================== --- PyWireGate/trunk/DSupdate.py (rev 0) +++ PyWireGate/trunk/DSupdate.py 2010-11-03 13:17:57 UTC (rev 65) @@ -0,0 +1,161 @@ +import getopt +import ConfigParser +try: + import cPickle as pickle +except ImportError: + import pickle + +try: + import json +except ImportError: + import simplejson as json + + +import datastore + +import sys + +class dbloader: + def __init__(self,config,fname): + self.config = config + self.dataobjects = {} + ## load datastore + self.load() + if config['type'].upper() == "KNX": + self.KNXloader(fname) + elif config['type'].upper() == "OWFS": + self.OWFSloader(fname) + self.save() + + def readConfig(self,configfile): + cfile = open(configfile,"r") + ## fix for missingsectionheaders + while True: + pos = cfile.tell() + if cfile.readline().startswith("["): + break + cfile.seek(pos) + config = {} + configparse = ConfigParser.SafeConfigParser() + configparse.readfp(cfile) + for section in configparse.sections(): + options = configparse.options(section) + config[section] = {} + for opt in options: + try: + config[section][opt] = configparse.getint(section,opt) + except ValueError: + try: + config[section][opt] = configparse.getfloat(section,opt) + except ValueError: + config[section][opt] = configparse.get(section,opt) + + return config + + def KNXloader(self,fname): + ga = self.readConfig(fname) + for key in ga.keys(): + id = "%s:%s" % (self.config['namespace'],key) + self.dataobjects[id] = datastore.dataObject(False,id,unicode(ga[key]['name'],errors='ignore')) + self.dataobjects[id].config['dptid'] = ga[key]['dptsubid'] + + def OWFSloader(self,fname): + ow = self.readConfig(fname) + for key in ow.keys(): + id = "%s:%s_temperature" % (self.config['namespace'],key) + print "add %s " % id + self.dataobjects[id] = datastore.dataObject(False,id,unicode(ow[key]['name'],errors='ignore')) + if 'resolution' in ow[key]: + self.dataobjects[id].config['resolution'] = ow[key]['resolution'] + if 'eib_ga_temp' in ow[key]: + if len(ow[key]['eib_ga_temp']) >0: + knxid = "KNX:%s" % ow[key]['eib_ga_temp'] + print "Try to attach to %s " % knxid + self.dataobjects[id].connected.append(knxid) + print "attaached" + + + def debug(self,msg=''): + print msg + + def load(self): + ## TODO: + self.debug("load DATASTORE") + try: + db = open(self.config['datastore'],"rb") + #loaddict = pickle.Unpickler(db).load() + loaddict = json.load(db) + db.close() + for name, obj in loaddict.items(): + self.dataobjects[name] = datastore.dataObject(False,obj['id'],obj['name']) + self.dataobjects[name].lastupdate = obj['lastupdate'] + self.dataobjects[name].config = obj['config'] + self.dataobjects[name].connected = obj['connected'] + self.debug("%d entries loaded in DATASTORE" % len(self.dataobjects)) + except: + ## no DB File + print "DB not found" + pass + ## Fixme: should belong to conncetor + + + + def save(self): + ## TODO: + self.debug("save DATASTORE") + savedict = {} + ## FIXME: user create a __reduce__ method for the Datastoreitem object + for name,obj in self.dataobjects.items(): + savedict[name] = { + 'name' : obj.name, + 'id' : obj.id, + 'value' : obj.value, + 'lastupdate' : obj.lastupdate, + 'config' : obj.config, + 'connected' : obj.connected + } + dbfile = open(self.config['datastore'],"wb") + #db = pickle.Pickler(dbfile,-1) + #db.dump(savedict) + json.dump(savedict,dbfile,sort_keys=True,indent=3) + dbfile.close() + for i in savedict.keys(): + if len(savedict[i]['connected'])>0: + print savedict[i] + + +if __name__ == "__main__": + import os + import sys + import getopt + try: + opts, args = getopt.getopt(sys.argv[1:], "f:d:n:t:", ["file=","datastore=","namespace=","type="]) + except getopt.GetoptError: + print "Fehler" + sys.exit(2) + config = { + 'datastore' : 'datastore.db', + 'namespace' : 'KNX', + 'type' : False + } + fname = False + for opt, arg in opts: + if opt in ("-d","--datastore"): + config['datastore'] = arg + + if opt in ("-n","--namespace"): + config['namespace'] = arg + + if opt in ("-t","--type"): + config['type'] = arg + + if opt in ("-f","--file"): + fname = arg + + if not fname: + print "no configfilename" + sys.exit(1) + if not config['type']: + config['type'] = config['namespace'] + dbloader(config,fname) + Modified: PyWireGate/trunk/WireGate.py =================================================================== --- PyWireGate/trunk/WireGate.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/WireGate.py 2010-11-03 13:17:57 UTC (rev 65) @@ -58,6 +58,7 @@ self.config = self.readConfig("/etc/wiregate/pywiregate.conf") defaultconfig = { 'pidfile' : "%s/wiregated.pid" % self.scriptpath, + 'datastore' : "%s/datastore.db" % self.scriptpath, 'logfile' : "%s/wiregated.log" % self.scriptpath, 'errorlog' : "%s/wiregated-error.log" % self.scriptpath, 'loglevel': 'info' @@ -148,6 +149,7 @@ ##Set Permissions os.chown(self.config['WireGate']['pidfile'],runasuser[2],runasuser[3]) os.chown(self.config['WireGate']['logfile'],runasuser[2],runasuser[3]) + os.chown(self.config['WireGate']['datastore'],runasuser[2],runasuser[3]) os.setregid(runasuser[3],runasuser[3]) os.setreuid(runasuser[2],runasuser[2]) @@ -251,8 +253,6 @@ ## Logger for all instances that check/create logger based on Configfile def log(self,msg,severity="info",instance="WireGate"): - LEVELS = {'debug': logging.debug,'info': logging.info,'warning': logging.warning,'warn': logging.warning,'error': logging.error,'critical': logging.critical} - level = LEVELS.get(severity, logging.info) try: logger = self.LOGGER[instance] except KeyError: @@ -262,8 +262,12 @@ logger.debug(msg) elif severity=="info": logger.info(msg) + elif severity=="notice": + logger.info(msg) elif severity=="warning": logger.warning(msg) + elif severity=="warn": + logger.warning(msg) elif severity=="error": logger.error(msg) elif severity=="critical": Modified: PyWireGate/trunk/connector.py =================================================================== --- PyWireGate/trunk/connector.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/connector.py 2010-11-03 13:17:57 UTC (rev 65) @@ -47,6 +47,10 @@ pass + def setValue(self, dsobj): + self.log("unconfigured setValue in %r called for %s" % (self,dsobj.name) ,'warn','WireGate') + pass + import SocketServer import socket class ConnectorServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer,Connector): Modified: PyWireGate/trunk/datastore.py =================================================================== --- PyWireGate/trunk/datastore.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/datastore.py 2010-11-03 13:17:57 UTC (rev 65) @@ -1,7 +1,19 @@ import time import threading +try: + import cPickle as pickle +except ImportError: + import pickle +try: + import json +except ImportError: + import simplejson as json + +import sys +import xml.dom.minidom + class datastore: """ Datastore Instance @@ -16,23 +28,15 @@ ## #################################################### self.WG = WireGateInstance + self.log("DATASTORE starting up") self.dataobjects = {} - + self.locked = threading.RLock() + self.locked.acquire() + self.xmltag = lambda x,y,z='': len(z)>0 and "<%s %s>%s</%s>" % (x,z,y,x) or "<%s>%s</%s>" % (x,y,x) ## Load XML Database self.load() - ## Fixme: should belong to conncetor - self.readgaconf() - - ## FIXME: that should belong to the Connector - def readgaconf(self): - ga = self.WG.readConfig("/etc/wiregate/eibga.conf") - for key in ga.keys(): - obj = self.get("KNX:%s" % key) - obj.dptid = ga[key]['dptsubid'] - obj.name = ga[key]['name'] - def update(self,id,val): ## Update the communication Object with value #################################################### @@ -44,14 +48,23 @@ ## update or create a Datastoreobject ## schould be used by all connectors to set their Values #################################################### + ## ## get the Datastore object obj = self.get(id) self.debug("Updating %s (%s): %r" % (obj.name,id,val)) ## Set the value of the object obj.setValue(val) - + ##TODO: central subscriber function for other connectore or servers + + for attached in obj.connected: + try: + self.dataobjects[attached].setValue(val,True) + except: + print "FAILED %s" % attached + __import__('traceback').print_exc(file=__import__('sys').stdout) + pass ## return the object for additional updates @@ -66,6 +79,7 @@ ## returns or create and returns the Dataobejct with ID id ## #################################################### + self.locked.acquire() try: ## check for existence type(self.dataobjects[id]) @@ -73,18 +87,88 @@ ## create a new one if it don't exist self.dataobjects[id] = dataObject(self.WG,id) ## return it + self.locked.release() return self.dataobjects[id] + ## FIXME: that should belong to the Connector + def readgaconf(self): + print "SHOULD NOT BE CALLED" + ga = self.WG.readConfig("/etc/wiregate/eibga.conf") + for key in ga.keys(): + obj = self.get("KNX:%s" % key) + obj.config['dptid'] = ga[key]['dptsubid'] + obj.name = ga[key]['name'] + obj._send = self.WG.connectors['KNX'].send + + def load(self): ## TODO: self.debug("load DATASTORE") - pass + try: + db = open(self.WG.config['WireGate']['datastore'],"rb") + #loaddict = pickle.Unpickler(db).load() + loaddict = json.load(db) + db.close() + for name, obj in loaddict.items(): + self.dataobjects[name] = dataObject(self.WG,obj['id'],obj['name']) + self.dataobjects[name].lastupdate = obj['lastupdate'] + self.dataobjects[name].config = obj['config'] + self.dataobjects[name].connected = obj['connected'] + self.debug("%d entries loaded in DATASTORE" % len(self.dataobjects)) + self.locked.release() + except IOError: + ## no DB File + pass + ## Fixme: should belong to conncetor + self.locked.release() + self.readgaconf() + + except: + ## error + pass + def save(self): ## TODO: self.debug("save DATASTORE") - pass + self.locked.acquire() + savedict = {} + ## FIXME: user create a __reduce__ method for the Datastoreitem object + for name,obj in self.dataobjects.items(): + savedict[name] = { + 'name' : obj.name, + 'id' : obj.id, + 'value' : obj.value, + 'lastupdate' : obj.lastupdate, + 'config' : obj.config, + 'connected' : obj.connected + } + dbfile = open(self.WG.config['WireGate']['datastore'],"wb") + #db = pickle.Pickler(dbfile,-1) + #db.dump(savedict) + json.dump(savedict,dbfile,sort_keys=True,indent=3) + dbfile.close() + + + def savetoXML(self): + objitemxml = "" + for name,obj in self.dataobjects.items(): + configxml = "" + for cname,cval in obj.config.items(): + configxml += self.xmltag(cname,cval) + objitemxml += self.xmltag( + "DSitem", + self.xmltag("id",name) + + self.xmltag("value",obj.getValue(),'type=%r' % type(obj.value).__name__) + + self.xmltag("config",configxml) + ) + self.locked.release() + xmlout = xml.dom.minidom.parseString(self.xmltag("Datastore",objitemxml)) + #xmlout = xmlout.toprettyxml(indent=" ") + xmlout = xmlout.toxml() + ## write binary to preserve UTF8 + open(self.WG.config['WireGate']['datastore'],"wb").write(xmlout) def debug(self,msg): #################################################### @@ -109,6 +193,7 @@ ## Threadlocking self.write_mutex = threading.RLock() self.read_mutex = threading.RLock() + ## check for namespace namespace = id.split(":",1) if len(namespace)>1: @@ -116,10 +201,14 @@ else: ## Fixme: maybe default Namespace namespace = "" + self.namespace = namespace + + if not name: + ## Initial Name + self.name = "%s:unbekannt-%s" % (namespace, time.strftime("%Y-%m-%d_%H:%M:%S")) + else: + self.name = name - ## Initial Name - self.name = "%s:unbekannt-%s" % (namespace, time.strftime("%Y-%m-%d_%H:%M:%S")) - ## some defaults self.value = "" self.lastupdate = 0 @@ -132,9 +221,18 @@ self.config = {} ## connected Logics, communication objects ... goes here - self.connected = {} + self.connected = [] - def setValue(self,val): + def _setValue(self,refered_self): + ## self override + print "Ovveride now" + if self.namespace: + self._setValue = self.WG.connectors[self.namespace].setValue + self.WG.connectors[self.namespace].setValue(refered_self) + ## override with connector send function + pass + + def setValue(self,val,send=False): try: ## get read lock self.read_mutex.acquire() @@ -143,6 +241,8 @@ ## save the modified time self.lastupdate = time.time() self.value = val + if send: + self._setValue(self) finally: ## release locks self.write_mutex.release() @@ -160,3 +260,39 @@ +#import json + +def JSON2DataStore(text): + obj = {} + return obj + + +def DataStore2JSON(obj): + text = "" + return text + +class testtwo: + def __init__(self): + self.i=10 + def _send(self,val): + """Hallo""" + print str(dir(self)) +str(val+self.i) + +class testthree: + def __init__(self): + self.u=1 + def send(self,val): + """its me""" + print str(dir(self)) +str(self.u) + + + +if __name__ == "__main__": + two = testtwo() + two._send(20) + three = testthree() + two._send = three.send + two._send(20) + print two._send + print dir(two) + \ No newline at end of file Modified: PyWireGate/trunk/knx_connector/BusMonitor.py =================================================================== --- PyWireGate/trunk/knx_connector/BusMonitor.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/knx_connector/BusMonitor.py 2010-11-03 13:17:57 UTC (rev 65) @@ -20,11 +20,12 @@ import time class busmonitor: - def __init__(self, WireGateInstance): + def __init__(self, WireGateInstance,connectorInstance): self.WG = WireGateInstance + self.KNX = connectorInstance self.nicehex=lambda x: " ".join(map(lambda y:"%.2x" % y,x)) self.tobinstr=lambda n,b=8: "".join([str((n >> y) & 1) for y in range(b-1, -1, -1)]) - self.dpt = DPT_Types.dpt_type() + self.dpt = DPT_Types.dpt_type(WireGateInstance) ## FIXME: Not fully implemented self.apcicodes = { @@ -99,8 +100,9 @@ if msg['ctrl2']['DestAddrType'] == 0 and msg['apdu']['tpdu'] == "T_DATA_XXX_REQ": msg['dstaddr'] = self._decodeGrpAddr(buf[3:5]) - id = "KNX:%s" % msg['dstaddr'] + id = "%s:%s" % (self.KNX.instanceName, msg['dstaddr']) + ## search Datastoreobject dsobj = self.WG.DATASTORE.get(id) ## Decode the DPT Value @@ -121,12 +123,8 @@ return msg - def errormsg(self,msg=''): - f=open("/tmp/WGerror","a+") - __import__('traceback').print_exc(file=f) - f.write(time.asctime()) - f.write("MSG:"+repr(msg)) - f.close() + def errormsg(self,msg=False): + self.WG.errorlog(msg) def _decodeCtrlField1(self,raw): Modified: PyWireGate/trunk/knx_connector/DPT_Types.py =================================================================== --- PyWireGate/trunk/knx_connector/DPT_Types.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/knx_connector/DPT_Types.py 2010-11-03 13:17:57 UTC (rev 65) @@ -21,7 +21,7 @@ ### sondern als LIST mit den dezimalen Werten ist das decode hier ein bischen angepasst class dpt_type: - def __init__(self,WireGateInstance=False): + def __init__(self,WireGateInstance): self.WG = WireGateInstance self.DECODER = { 1:self.decodeDPT1, # EIS 1/7 / 1 bit 0=Aus/1=Ein @@ -50,7 +50,8 @@ if dptid > 0: dpt = dptid elif dsobj: - dpt = dsobj.dptid + if "dptid" in dsobj.config: + dpt = dsobj.config['dptid'] else: return False if dpt == -1: @@ -75,13 +76,18 @@ self.errormsg() return raw - def errormsg(self,msg=''): - __import__('traceback').print_exc(file=__import__('sys').stdout) + def errormsg(self,msg=False): + self.WG.errormsg(msg) def debug(self,msg): - #print msg - pass + self.log(msg,'debug') + + def log(self,msg,severity='info',instance=False): + if not instance: + instance = "dpt-types" + self.WG.log(msg,severity,instance) + def toBigInt(self,raw): c=0 res = 0 @@ -212,6 +218,7 @@ def decodeDPT16(self,raw): res = "" for char in raw: + ## stop on terminating \x00 if char == 0: break res += chr(char) Modified: PyWireGate/trunk/knx_connector/GroupSocket.py =================================================================== --- PyWireGate/trunk/knx_connector/GroupSocket.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/knx_connector/GroupSocket.py 2010-11-03 13:17:57 UTC (rev 65) @@ -20,11 +20,12 @@ import time class groupsocket: - def __init__(self, WireGateInstance): + def __init__(self, WireGateInstance, connectorInstance): self.WG = WireGateInstance + self.KNX = connectorInstance self.nicehex=lambda x: " ".join(map(lambda y:"%.2x" % y,x)) self.tobinstr=lambda n,b=8: "".join([str((n >> y) & 1) for y in range(b-1, -1, -1)]) - self.dpt = DPT_Types.dpt_type() + self.dpt = DPT_Types.dpt_type(WireGateInstance) def decode(self,buf,src,dst): ## Accept List Hex or Binary Data @@ -48,7 +49,7 @@ msg['srcaddr'] = self._decodePhysicalAddr(src) try: msg['dstaddr'] = self._decodeGrpAddr(dst) - id = "KNX:%s" % msg['dstaddr'] + id = "%s:%s" % (self.KNX.instanceName, msg['dstaddr']) if (buf[0] & 0x3 or (buf[1] & 0xC0) == 0xC0): ##FIXME: unknown APDU self.debug("unknown APDU from "+msg['srcaddr']+" to "+msg['dstaddr']+ " raw:"+buf) @@ -78,13 +79,9 @@ return msg - def errormsg(self,msg=''): - f=open("/tmp/WGerror","a+") - __import__('traceback').print_exc(file=f) - f.write(time.asctime()) - f.write("MSG:"+repr(msg)) - f.close() - + def errormsg(self,msg=False): + ## central error handling + self.WG.errorlog(msg) def _decodePhysicalAddr(self,raw): return "%d.%d.%d" % ((raw >> 12) & 0x0f, (raw >> 8) & 0x0f, (raw) & 0xff) @@ -93,7 +90,7 @@ return "%d/%d/%d" % ((raw >> 11) & 0x1f, (raw >> 8) & 0x07, (raw) & 0xff) def debug(self,msg): - print "DEBUG: GROUPSOCKET: "+ repr(msg) + #print "DEBUG: GROUPSOCKET: "+ repr(msg) pass Modified: PyWireGate/trunk/knx_connector/KNX_Connector.py =================================================================== --- PyWireGate/trunk/knx_connector/KNX_Connector.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/knx_connector/KNX_Connector.py 2010-11-03 13:17:57 UTC (rev 65) @@ -35,8 +35,8 @@ self.KNXBuffer = EIBConnection.EIBBuffer() self.KNXSrc = EIBConnection.EIBAddr() self.KNXDst = EIBConnection.EIBAddr() - self.busmon = BusMonitor.busmonitor(WireGateInstance) - self.groupsocket = GroupSocket.groupsocket(WireGateInstance) + self.busmon = BusMonitor.busmonitor(WireGateInstance,self) + self.groupsocket = GroupSocket.groupsocket(WireGateInstance,self) ## Deafaultconfig defaultconfig = { @@ -82,7 +82,7 @@ def _run(self): while self.isrunning: ## Check if we are alive and responde until 10 secs - self.WG.watchdog("knx_connector",10) + self.WG.watchdog(self.instanceName,10) try: vbusmonin, vbusmonout, vbusmonerr = select.select([self.KNX.EIB_Poll_FD()],[],[],1) except: @@ -114,3 +114,7 @@ if len(self.KNXBuffer.buffer) > 7 : self.busmon.decode(self.KNXBuffer.buffer) + + + def send(self,dsobj): + print "SEND to %s" % dsobj.name \ No newline at end of file Modified: PyWireGate/trunk/owfs_connector/OWFS_Connector.py =================================================================== --- PyWireGate/trunk/owfs_connector/OWFS_Connector.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/owfs_connector/OWFS_Connector.py 2010-11-03 13:17:57 UTC (rev 65) @@ -172,7 +172,7 @@ ## loop through their interfaces for get in self.busmaster[busname]['sensors'][sensor]['interfaces']: resolution = "" - id = "OW:"+sensor+"_"+get + id = "%s:%s_%s" % (self.instanceName,sensor,get) ## get the Datastore Object and look for config obj = self.WG.DATASTORE.get(id) @@ -205,4 +205,3 @@ threadname = "OWFS-Reader_%s" % busname self.busmaster[busname]['readthread'] = threading.Thread(target=self._read,args=[busname],name=threadname) self.busmaster[busname]['readthread'].start() - \ No newline at end of file Modified: PyWireGate/trunk/owfs_connector/connection.py =================================================================== --- PyWireGate/trunk/owfs_connector/connection.py 2010-11-01 21:14:31 UTC (rev 64) +++ PyWireGate/trunk/owfs_connector/connection.py 2010-11-03 13:17:57 UTC (rev 65) @@ -88,6 +88,7 @@ self._server = server self._port = port + self.checknum = re.compile(r"(^\d+$)|(^\d+\x2e\d+$)", re.MULTILINE) def __str__(self): @@ -121,91 +122,120 @@ """ """ - #print 'Connection.read("%s", %i, "%s")' % (path) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((self._server, self._port)) + #print 'Connection.read("%s")' % (path) + + rtn = None + ## we don't want errors + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect((self._server, self._port)) + except: + ## + return rtn - smsg = self.pack(OWMsg.read, len(path) + 1, 8192) - s.sendall(smsg) - s.sendall(path + '\x00') + smsg = self.pack(OWMsg.read, len(path) + 1, 8192) + s.sendall(smsg) + s.sendall(path + '\x00') - while 1: - data = s.recv(24) + while 1: + try: + data = s.recv(24) + except: + ## + return rtn - if len(data) is not 24: - raise exShortRead + payload_len = -1 + if len(data) is 24: + ret, payload_len, data_len = self.unpack(data) - ret, payload_len, data_len = self.unpack(data) + if payload_len >= 0: + data = s.recv(payload_len) + return self.toNumber(data[:data_len]) + break + else: + # ping response + return None - if payload_len >= 0: - data = s.recv(payload_len) - rtn = self.toNumber(data[:data_len]) - break - else: - # ping response - rtn = None - break + finally: + s.close() + - s.close() - return rtn - def write(self, path, value): """ """ + ret = None + try: + #print 'Connection.write("%s", "%s")' % (path, str(value)) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect((self._server, self._port)) + except: + return ret - #print 'Connection.write("%s", "%s")' % (path, str(value)) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((self._server, self._port)) + value = str(value) + smsg = self.pack(OWMsg.write, len(path) + 1 + len(value) + 1, len(value) + 1) + s.sendall(smsg) + s.sendall(path + '\x00' + value + '\x00') - value = str(value) - smsg = self.pack(OWMsg.write, len(path) + 1 + len(value) + 1, len(value) + 1) - s.sendall(smsg) - s.sendall(path + '\x00' + value + '\x00') + try: + data = s.recv(24) + except: + return ret - data = s.recv(24) + if len(data) is 24: + ret, payload_len, data_len = self.unpack(data) + return ret - if len(data) is not 24: - raise exShortRead + + finally: + s.close() + - ret, payload_len, data_len = self.unpack(data) - s.close() - return ret - - def dir(self, path): """ """ + + fields = [] + try: + #print 'Connection.dir("%s")' % (path) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect((self._server, self._port)) + except: + return fields - #print 'Connection.dir("%s")' % (path) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((self._server, self._port)) + smsg = self.pack(OWMsg.dir, len(path) + 1, 0) + s.sendall(smsg) + s.sendall(path + '\x00') - smsg = self.pack(OWMsg.dir, len(path) + 1, 0) - s.sendall(smsg) - s.sendall(path + '\x00') + while 1: + try: + data = s.recv(24) + except: + return fields - fields = [] - while 1: - data = s.recv(24) + if len(data) is not 24: + return fields - if len(data) is not 24: - raise exShortRead + ret, payload_len, data_len = self.unpack(data) - ret, payload_len, data_len = self.unpack(data) + if payload_len > 0: + try: + data = s.recv(payload_len) + except: + return fields + fields.append(data[:data_len]) + else: + # end of dir list or 'ping' response + return fields - if payload_len > 0: - data = s.recv(payload_len) - fields.append(data[:data_len]) - else: - # end of dir list or 'ping' response - break + finally: + s.close() - s.close() - return fields - def pack(self, function, payload_len, data_len): """ """ @@ -241,15 +271,15 @@ return ret_value, payload_len, data_len - def toNumber(self, str): + def toNumber(self, owstr): """ """ + owstr = owstr.strip() + numresult = self.checknum.findall(owstr) + if numresult: + if numresult[0][0]: + return int(numresult[0][0]) + elif numresult[0][1]: + return float(numresult[0][1]) - stripped = str.strip() - if re.compile('^-?\d+$').match(stripped) : - return int(stripped) - - if re.compile('^-?\d*\.\d*$').match(stripped) : # Could crash if it matched '.' - let it. - return float(stripped) - - return str + return owstr Added: PyWireGate/trunk/simplejson/.___init__.py =================================================================== (Binary files differ) Property changes on: PyWireGate/trunk/simplejson/.___init__.py ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: PyWireGate/trunk/simplejson/._decoder.py =================================================================== (Binary files differ) Property changes on: PyWireGate/trunk/simplejson/._decoder.py ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: PyWireGate/trunk/simplejson/._scanner.py =================================================================== (Binary files differ) Property changes on: PyWireGate/trunk/simplejson/._scanner.py ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: PyWireGate/trunk/simplejson/__init__.py =================================================================== --- PyWireGate/trunk/simplejson/__init__.py (rev 0) +++ PyWireGate/trunk/simplejson/__init__.py 2010-11-03 13:17:57 UTC (rev 65) @@ -0,0 +1,437 @@ +r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of +JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data +interchange format. + +:mod:`simplejson` exposes an API familiar to users of the standard library +:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained +version of the :mod:`json` library contained in Python 2.6, but maintains +compatibility with Python 2.4 and Python 2.5 and (currently) has +significant performance advantages, even without using the optional C +extension for speedups. + +Encoding basic Python object hierarchies:: + + >>> import simplejson as json + >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) + '["foo", {"bar": ["baz", null, 1.0, 2]}]' + >>> print json.dumps("\"foo\bar") + "\"foo\bar" + >>> print json.dumps(u'\u1234') + "\u1234" + >>> print json.dumps('\\') + "\\" + >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) + {"a": 0, "b": 0, "c": 0} + >>> from StringIO import StringIO + >>> io = StringIO() + >>> json.dump(['streaming API'], io) + >>> io.getvalue() + '["streaming API"]' + +Compact encoding:: + + >>> import simplejson as json + >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) + '[1,2,3,{"4":5,"6":7}]' + +Pretty printing:: + + >>> import simplejson as json + >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=' ') + >>> print '\n'.join([l.rstrip() for l in s.splitlines()]) + { + "4": 5, + "6": 7 + } + +Decoding JSON:: + + >>> import simplejson as json + >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] + >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj + True + >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' + True + >>> from StringIO import StringIO + >>> io = StringIO('["streaming API"]') + >>> json.load(io)[0] == 'streaming API' + True + +Specializing JSON object decoding:: + + >>> import simplejson as json + >>> def as_complex(dct): + ... if '__complex__' in dct: + ... return complex(dct['real'], dct['imag']) + ... return dct + ... + >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', + ... object_hook=as_complex) + (1+2j) + >>> from decimal import Decimal + >>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1') + True + +Specializing JSON object encoding:: + + >>> import simplejson as json + >>> def encode_complex(obj): + ... if isinstance(obj, complex): + ... return [obj.real, obj.imag] + ... raise TypeError(repr(o) + " is not JSON serializable") + ... + >>> json.dumps(2 + 1j, default=encode_complex) + '[2.0, 1.0]' + >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) + '[2.0, 1.0]' + >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) + '[2.0, 1.0]' + + +Using simplejson.tool from the shell to validate and pretty-print:: + + $ echo '{"json":"obj"}' | python -m simplejson.tool + { + "json": "obj" + } + $ echo '{ 1.2:3.4}' | python -m simplejson.tool + Expecting property name: line 1 column 2 (char 2) +""" +__version__ = '2.1.2' +__all__ = [ + 'dump', 'dumps', 'load', 'loads', + 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', + 'OrderedDict', +] + +__author__ = 'Bob Ippolito <bo...@re...>' + +from decimal import Decimal + +from decoder import JSONDecoder, JSONDecodeError +from encoder import JSONEncoder +def _import_OrderedDict(): + import collections + try: + return collections.OrderedDict + except AttributeError: + import ordered_dict + return ordered_dict.OrderedDict +OrderedDict = _import_OrderedDict() + +def _import_c_make_encoder(): + try: + from simplejson._speedups import make_encoder + return make_encoder + except ImportError: + return None + +_default_encoder = JSONEncoder( + skipkeys=False, + ensure_ascii=True, + check_circular=True, + allow_nan=True, + indent=None, + separators=None, + encoding='utf-8', + default=None, + use_decimal=False, +) + +def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, + allow_nan=True, cls=None, indent=None, separators=None, + encoding='utf-8', default=None, use_decimal=False, **kw): + """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a + ``.write()``-supporting file-like object). + + If ``skipkeys`` is true then ``dict`` keys that are not basic types + (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) + will be skipped instead of raising a ``TypeError``. + + If ``ensure_ascii`` is false, then the some chunks written to ``fp`` + may be ``unicode`` instances, subject to normal Python ``str`` to + ``unicode`` coercion rules. Unless ``fp.write()`` explicitly + understands ``unicode`` (as in ``codecs.getwriter()``) this is likely + to cause an error. + + If ``check_circular`` is false, then the circular reference check + for container types will be skipped and a circular reference will + result in an ``OverflowError`` (or worse). + + If ``allow_nan`` is false, then it will be a ``ValueError`` to + serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) + in strict compliance of the JSON specification, instead of using the + JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). + + If *indent* is a string, then JSON array elements and object members + will be pretty-printed with a newline followed by that string repeated + for each level of nesting. ``None`` (the default) selects the most compact + representation without any newlines. For backwards compatibility with + versions of simplejson earlier than 2.1.0, an integer is also accepted + and is converted to a string with that many spaces. + + If ``separators`` is an ``(item_separator, dict_separator)`` tuple + then it will be used instead of the default ``(', ', ': ')`` separators. + ``(',', ':')`` is the most compact JSON representation. + + ``encoding`` is the character encoding for str instances, default is UTF-8. + + ``default(obj)`` is a function that should return a serializable version + of obj or raise TypeError. The default simply raises TypeError. + + If *use_decimal* is true (default: ``False``) then decimal.Decimal + will be natively serialized to JSON with full precision. + + To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the + ``.default()`` method to serialize additional types), specify it with + the ``cls`` kwarg. + + """ + # cached encoder + if (not skipkeys and ensure_ascii and + check_circular and allow_nan and + cls is None and indent is None and separators is None and + encoding == 'utf-8' and default is None and not kw): + iterable = _default_encoder.iterencode(obj) + else: + if cls is None: + cls = JSONEncoder + iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, + check_circular=check_circular, allow_nan=allow_nan, indent=indent, + separators=separators, encoding=encoding, + default=default, use_decimal=use_decimal, **kw).iterencode(obj) + # could accelerate with writelines in some versions of Python, at + # a debuggability cost + for chunk in iterable: + fp.write(chunk) + + +def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, + allow_nan=True, cls=None, indent=None, separators=None, + encoding='utf-8', default=None, use_decimal=False, **kw): + """Serialize ``obj`` to a JSON formatted ``str``. + + If ``skipkeys`` is false then ``dict`` keys that are not basic types + (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) + will be skipped instead of raising a ``TypeError``. + + If ``ensure_ascii`` is false, then the return value will be a + ``unicode`` instance subject to normal Python ``str`` to ``unicode`` + coercion rules instead of being escaped to an ASCII ``str``. + + If ``check_circular`` is false, then the circular reference check + for container types will be skipped and a circular reference will + result in an ``OverflowError`` (or worse). + + If ``allow_nan`` is false, then it will be a ``ValueError`` to + serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in + strict compliance of the JSON specification, instead of using the + JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). + + If ``indent`` is a string, then JSON array elements and object members + will be pretty-printed with a newline followed by that string repeated + for each level of nesting. ``None`` (the default) selects the most compact + representation without any newlines. For backwards compatibility with + versions of simplejson earlier than 2.1.0, an integer is also accepted + and is converted to a string with that many spaces. + + If ``separators`` is an ``(item_separator, dict_separator)`` tuple + then it will be used instead of the default ``(', ', ': ')`` separators. + ``(',', ':')`` is the most compact JSON representation. + + ``encoding`` is the character encoding for str instances, default is UTF-8. + + ``default(obj)`` is a function that should return a serializable version + of obj or raise TypeError. The default simply raises TypeError. + + If *use_decimal* is true (default: ``False``) then decimal.Decimal + will be natively serialized to JSON with full precision. + + To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the + ``.default()`` method to serialize additional types), specify it with + the ``cls`` kwarg. + + """ + # cached encoder + if (not skipkeys and ensure_ascii and + check_circular and allow_nan and + cls is None and indent is None and separators is None and + encoding == 'utf-8' and default is None and not use_decimal + and not kw): + return _default_encoder.encode(obj) + if cls is None: + cls = JSONEncoder + return cls( + skipkeys=skipkeys, ensure_ascii=ensure_ascii, + check_circular=check_circular, allow_nan=allow_nan, indent=indent, + separators=separators, encoding=encoding, default=default, + use_decimal=use_decimal, **kw).encode(obj) + + +_default_decoder = JSONDecoder(encoding=None, object_hook=None, + object_pairs_hook=None) + + +def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, + parse_int=None, parse_constant=None, object_pairs_hook=None, + use_decimal=False, **kw): + """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing + a JSON document) to a Python object. + + *encoding* determines the encoding used to interpret any + :class:`str` objects decoded by this instance (``'utf-8'`` by + default). It has no effect when decoding :class:`unicode` objects. + + Note that currently only encodings that are a superset of ASCII work, + strings of other encodings should be passed in as :class:`unicode`. + + *object_hook*, if specified, will be called with the result of every + JSON object decoded and its return value will be used in place of the + given :class:`dict`. This can be used to provide custom + deserializations (e.g. to support JSON-RPC class hinting). + + *object_pairs_hook* is an optional function that will be called with + the result of any object literal decode with an ordered list of pairs. + The return value of *object_pairs_hook* will be used instead of the + :class:`dict`. This feature can be used to implement custom decoders + that rely on the order that the key and value pairs are decoded (for + example, :func:`collections.OrderedDict` will remember the order of + insertion). If *object_hook* is also defined, the *object_pairs_hook* + takes priority. + + *parse_float*, if specified, will be called with the string of every + JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser + for JSON floats (e.g. :class:`decimal.Decimal`). + + *parse_int*, if specified, will be called with the string of every + JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser + for JSON integers (e.g. :class:`float`). + + *parse_constant*, if specified, will be called with one of the + following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This + can be used to raise an exception if invalid JSON numbers are + encountered. + + If *use_decimal* is true (default: ``False``) then it implies + parse_float=decimal.Decimal for parity with ``dump``. + + To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` + kwarg. + + """ + return loads(fp.read(), + encoding=encoding, cls=cls, object_hook=object_hook, + parse_float=parse_float, parse_int=parse_int, + parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, + use_decimal=use_decimal, **kw) + + +def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, + parse_int=None, parse_constant=None, object_pairs_hook=None, + use_decimal=False, **kw): + """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON + document) to a Python object. + + *encoding* determines the encoding used to interpret any + :class:`str` objects decoded by this instance (``'utf-8'`` by + default). It has no effect when decoding :class:`unicode` objects. + + Note that currently only encodings that are a superset of ASCII work, + strings of other encodings should be passed in as :class:`unicode`. + + *object_hook*, if specified, will be called with the result of every + JSON object decoded and its return value will be used in place of the + given :class:`dict`. This can be used to provide custom + deserializations (e.g. to support JSON-RPC class hinting). + + *object_pairs_hook* is an optional function that will be called with + the result of any object literal decode with an ordered list of pairs. + The return value of *object_pairs_hook* will be used instead of the + :class:`dict`. This feature can be used to implement custom decoders + that rely on the order that the key and value pairs are decoded (for + example, :func:`collections.OrderedDict` will remember the order of + insertion). If *object_hook* is also defined, the *object_pairs_hook* + takes priority. + + *parse_float*, if specified, will be called with the string of every + JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser + for JSON floats (e.g. :class:`decimal.Decimal`). + + *parse_int*, if specified, will be called with the string of every + JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser + for JSON integers (e.g. :class:`float`). + + *parse_constant*, if specified, will be called with one of the + following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This + can be used to raise an exception if invalid JSON numbers are + encountered. + + If *use_decimal* is true (default: ``False``) then it implies + parse_float=decimal.Decimal for parity with ``dump``. + + To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` + kwarg. + + """ + if (cls is None and encoding is None and object_hook is None and + parse_int is None and parse_float is None and + parse_constant is None and object_pairs_hook is None + and not use_decimal and not kw): + return _default_decoder.decode(s) + if cls is None: + cls = JSONDecoder + if object_hook is not None: + kw['object_hook'] = object_hook + if object_pairs_hook is not None: + kw['object_pairs_hook'] = object_pairs_hook + if parse_float is not None: + kw['parse_float'] = parse_float + if parse_int is not None: + kw['parse_int'] = parse_int + if parse_constant is not None: + kw['parse_constant'] = parse_constant + if use_decimal: + if parse_float is not None: + raise TypeError("use_decimal=True implies parse_float=Decimal") + kw['parse_float'] = Decimal + return cls(encoding=encoding, **kw).decode(s) + + +def _toggle_speedups(enabled): + import simplejson.decoder as dec + import simplejson.encoder as enc + import simplejson.scanner as scan + c_make_encoder = _import_c_make_encoder() + if enabled: + dec.scanstring = dec.c_scanstring or dec.py_scanstring + enc.c_make_encoder = c_make_encoder + enc.encode_basestring_ascii = (enc.c_encode_basestring_ascii or + enc.py_encode_basestring_ascii) + scan.make_scanner = scan.c_make_scanner or scan.py_make_scanner + else: + dec.scanstring = dec.py_scanstring + enc.c_make_encoder = None + enc.encode_basestring_ascii = enc.py_encode_basestring_ascii + scan.make_scanner = scan.py_make_scanner + dec.make_scanner = scan.make_scanner + global _default_decoder + _default_decoder = JSONDecoder( + encoding=None, + object_hook=None, + object_pairs_hook=None, + ) + global _default_encoder + _default_encoder = JSONEncoder( + skipkeys=False, + ensure_ascii=True, + check_circular=True, + allow_nan=True, + indent=None, + separators=None, + encoding='utf-8', + default=None, + ) Added: PyWireGate/trunk/simplejson/_speedups.c =================================================================== --- PyWireGate/trunk/simplejson/_speedups.c (rev 0) +++ PyWireGate/trunk/simplejson/_speedups.c 2010-11-03 13:17:57 UTC (rev 65) @@ -0,0 +1,2561 @@ +#include "Python.h" +#include "structmember.h" +#if PY_VERSION_HEX < 0x02070000 && !defined(PyOS_string_to_double) +#define PyOS_string_to_double json_PyOS_string_to_double +static double +json_PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception); +static double +json_PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) { + double x; + assert(endptr == NULL); + assert(overflow_exception == NULL); + PyFPE_START_PROTECT("json_PyOS_string_to_double", return -1.0;) + x = PyOS_ascii_atof(s); + PyFPE_END_PROTECT(x) + return x; +} +#endif +#if PY_VERSION_HEX < 0x02060000 && !defined(Py_TYPE) +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#endif +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#define PyInt_FromSsize_t PyInt_FromLong +#define PyInt_AsSsize_t PyInt_AsLong +#endif +#ifndef Py_IS_FINITE +#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X)) +#endif + +#ifdef __GNUC__ +#define UNUSED __attribute__((__unused__)) +#else +#define UNUSED +#endif + +#define DEFAULT_ENCODING "utf-8" + +#define PyScanner_Check(op) PyObject_TypeCheck(op, &PyScannerType) +#define PyScanner_CheckExact(op) (Py_TYPE(op) == &PyScannerType) +#define PyEncoder_Check(op) PyObject_TypeCheck(op, &PyEncoderType) +#define PyEncoder_CheckExact(op) (Py_TYPE(op) == &PyEncoderType) +#define Decimal_Check(op) (PyObject_TypeCheck(op, DecimalTypePtr)) + +static PyTypeObject PyScannerType; +static PyTypeObject PyEncoderType; +static PyTypeObject *DecimalTypePtr; + +typedef struct _PyScannerObject { + PyObject_HEAD + PyObject *encoding; + PyObject *strict; + PyObject *object_hook; + PyObject *pairs_hook; + PyObject *parse_float; + PyObject *parse_int; + PyObject *parse_constant; + PyObject *memo; +} PyScannerObject; + +static PyMemberDef scanner_members[] = { + {"encoding", T_OBJECT, offsetof(PyScannerObject, encoding), READONLY, "encoding"}, + {"strict", T_OBJECT, offsetof(PyScannerObject, strict), READONLY, "strict"}, + {"object_hook", T_OBJECT, offsetof(PyScannerObject, object_hook), READONLY, "object_hook"}, + {"object_pairs_hook", T_OBJECT, offsetof(PyScannerObject, pairs_hook), READONLY, "object_pairs_hook"}, + {"parse_float", T_OBJECT, offsetof(PyScannerObject, parse_float), READONLY, "parse_float"}, + {"parse_int", T_OBJECT, offsetof(PyScannerObject, parse_int), READONLY, "parse_int"}, + {"parse_constant", T_OBJECT, offsetof(PyScannerObject, parse_constant), READONLY, "parse_constant"}, + {NULL} +}; + +typedef struct _PyEncoderObject { + PyObject_HEAD + PyObject *markers; + PyObject *defaultfn; + PyObject *encoder; + PyObject *indent; + PyObject *key_separator; + PyObject *item_separator; + PyObject *sort_keys; + PyObject *skipkeys; + PyObject *key_memo; + int fast_encode; + int allow_nan; + int use_decimal; +} PyEncoderObject; + +static PyMemberDef encoder_members[] = { + {"markers", T_OBJECT, offsetof(PyEncoderObject, markers), READONLY, "markers"}, + {"default", T_OBJECT, offsetof(PyEncoderObject, defaultfn), READONLY, "default"}, + {"encoder", T_OBJECT, offsetof(PyEncoderObject, encoder), READONLY, "encoder"}, + {"indent", T_OBJECT, offsetof(PyEncoderObject, indent), READONLY, "indent"}, + {"key_separator", T_OBJECT, offsetof(PyEncoderObject, key_separator), READONLY, "key_separator"}, + {"item_separator", T_OBJECT, offsetof(PyEncoderObject, item_separator), READONLY, "item_separator"}, + {"sort_keys", T_OBJECT, offsetof(PyEncoderObject, sort_keys), READONLY, "sort_keys"}, + {"skipkeys", T_OBJECT, offsetof(PyEncoderObject, skipkeys), READONLY, "skipkeys"}, + {"key_memo", T_OBJECT, offsetof(PyEncoderObject, key_memo), READONLY, "key_memo"}, + {NULL} +}; + +static Py_ssize_t +ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars); +static PyObject * +ascii_escape_unicode(PyObject *pystr); +static PyObject * +ascii_escape_str(PyObject *pystr); +static PyObject * +py_encode_basestring_ascii(PyObject* self UNUSED, PyObject *pystr); +void init_speedups(void); +static PyObject * +scan_once_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr); +static PyObject * +scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr); +static PyObject * +_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx); +static PyObject * +scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +static int +scanner_init(PyObject *self, PyObject *args, PyObject *kwds); +static void +scanner_dealloc(PyObject *self); +static int +scanner_clear(PyObject *self); +static PyObject * +encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +static int +encoder_init(PyObject *self, PyObject *args, PyObject *kwds); +static void +encoder_dealloc(PyObject *self); +static int +encoder_clear(PyObject *self); +static int +encoder_listencode_list(PyEncoderObject *s, PyObject *rval, PyObject *seq, Py_ssize_t indent_level); +static int +encoder_listencode_obj(PyEncoderObject *s, PyObject *rval, PyObject *obj, Py_ssize_t indent_level); +static int +encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ssize_t indent_level); +static PyObject * +_encoded_const(PyObject *obj); +static void +raise_errmsg(char *msg, PyObject *s, Py_ssize_t end); +static PyObject * +encoder_encode_string(PyEncoderObject *s, PyObject *obj); +static int +_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr); +static PyObject * +_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr); +static PyObject * +encoder_encode_float(PyEncoderObject *s, PyObject *obj); + +#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '"') +#define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r')) + +#define MIN_EXPANSION 6 +#ifdef Py_UNICODE_WIDE +#define MAX_EXPANSION (2 * MIN_EXPANSION) +#else +#define MAX_EXPANSION MIN_EXPANSION +#endif + +static int +_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr) +{ + /* PyObject to Py_ssize_t converter */ + *size_ptr = PyInt_AsSsize_t(o); + if (*size_ptr == -1 && PyErr_Occurred()) + return 0; + return 1; +} + +static PyObject * +_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr) +{ + /* Py_ssize_t to PyObject converter */ + return PyInt_FromSsize_t(*size_ptr); +} + +static Py_ssize_t +ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars) +{ + /* Escape unicode code point c to ASCII escape sequences + in char *output. output must have at least 12 bytes unused to + accommodate an escaped surrogate pair "\uXXXX\uXXXX" */ + output[chars++] = '\\'; + switch (c) { + case '\\': output[chars++] = (char)c; break; + case '"': output[chars++] = (char)c; break; + case '\b': output[chars++] = 'b'; break; + case '\f': output[chars++] = 'f'; break; + case '\n': output[chars++] = 'n'; break; + case '\r': output[chars++] = 'r'; break; + case '\t': output[chars++] = 't'; break; + default: +#ifdef Py_UNICODE_WIDE + if (c >= 0x10000) { + /* UTF-16 surrogate pair */ + Py_UNICODE v = c - 0x10000; + c = 0xd800 | ((v >> 10) & 0x3ff); + output[chars++] = 'u'; + output[... [truncated message content] |