<commit_before>"""
Main source tree (AntDevice) can already serve a as protocol
disassembler at least ant api protocol level. This is as work
in progress to help parse the data payload. This codes pretty
ugly, just looking from something to do while i wait for gps
device to acutally be delivered.
"""

import sys
import binascii
import re
import struct
import collections

ANT_ALL_FUNCTIONS = [
    ("unassignChannel", 0x41, "<B", ["channelNumber"]),
    ("assignChannel", 0x42, "<BBB", ["channelNumber", "channelType", "networkNumber"]),
    ("assignChannel", 0x42, "<BBBB", ["channelNumber", "channelType", "networkNumber", "extendedAttrs"]),
    ("setChannelId", 0x51, "<BHBB", ["channelNumber", "deviceNumber", "deviceTypeId", "transType"]),
    ("setChannelPeriod", 0x43, "<BH", ["channelNumber", "messagePeriod"]),
    ("setChannelSearchTimeout", 0x44, "<BB", ["channelNumber", "searchTimeout"]),
    ("setChannelRfFreq", 0x45, "<BB", ["channelNumber", "rfFrequency"]),
    ("setNetworkKey", 0x46, "<BQ", ["networkNumber", "key"]),
    ("setTransmitPower", 0x47, "<xB", ["txPower"]),
    ("addChannelId", 0x59, "<BHBBB", ["channelNumber", "deviceNumber", "deviceTypeId", "transType","listIndex"]),
    ("configList", 0x5A, "<BB?", ["channelNumber", "listSize", "exclude"]),
    ("setChannelTxPower", 0x60, "<BB", ["channelNumber", "txPower"]),
    ("setLowPriorityChannelSearchTimeout", 0x63, "<BB", ["channelNumber", "searchTimeout"]),
    ("setSerialNumChannelId", 0x65, "<BBB", ["channelNumber", "deviceTypeId", "transType"]),
    ("rxExtMesgsEnable", 0x66, "<x?", ["enable"]),
    ("enableLed", 0x68, "<x?", ["enable"]),
    ("crystalEnable", 0x6D, "<x", []),
    ("libConfig", 0x6E, "<xB", ["libConfig"]),
    ("configFrequencyAgility", 0x70, "<BBBB", ["channelNumber", "freq1", "freq2", "freq3"]),
    ("setProximitySearch", 0x71, "<BB", ["channelNumber", "searchThresholdId"]),
    ("setChannelSearchPriority", 0x75, "<BB", ["channelNumber", "searchPriority"]),
    ("resetSystem", 0x4A, "<x", []),
    ("openChannel", 0x4B, "<B", ["channelNumber"]),
    ("closeChannel", 0x4C, "<B", ["channelNumber"]),
    ("openRxScanMode", 0x5B, "<x", []),
    ("requestMessage", 0x4D, "<BB", ["channelNumber", "messageId"]),
    ("sleepMessage", 0xC5, "<x", []),
    ("sendBroadcastData", 0x4E, "<B8s", ["channelNumber", "data"]),
    ("sendAcknowledgedData", 0x4F, "<B8s", ["channelNumber", "data"]),
    ("sendBurstTransferPacket", 0x50, "<B8s", ["channelNumber", "data"]),
    ("initCWTestMode", 0x53, "<x", []),
    ("setCwTestMode", 0x48, "<xBB", ["txPower", "rfFreq"]),
    ("sendExtBroadcastData", 0x5D, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("sendExtAcknowledgedData", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("sendExtBurstTransferPacket", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
]

ANT_ALL_CALLBACKS = [
    ("startupMessage", 0x6F, "<B", ["startupMesssage"]),
    ("serialErrorMessage", 0xAE, "<B", ["errorNumber"]),
    ("broadcastData", 0x4E, "<B8s", ["channelNumber", "data"]),
    ("acknowledgedData", 0x4F, "<B8s", ["channelNumber", "data"]),
    ("burstTransferPacket", 0x50, "<B8s", ["channelNumber", "data"]),
    ("channelEvent", 0x40, "<BBB", ["channelNumber", "messageId", "messageCode"]),
    ("channelStatus", 0x52, "<BB", ["channelNumber", "channelStatus"]),
    ("channelId", 0x51, "<BHBB", ["channelNumber", "deviceNumber", "deviceTypeId", "manId"]),
    ("antVersion", 0x3E, "<11s", ["version"]),
    ("capabilities", 0x54, "<BBBBBB", ["maxChannels", "maxNetworks", "standardOptions", "advancedOptions", "advancedOptions2", "reserved"]),
    ("serialNumber", 0x61, "<4s", ["serialNumber"]),
    ("extBroadcastData", 0x5D, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("extAcknowledgedData", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("extBurstTransferPacket", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
]

class StructUnpacker(struct.Struct):
	"""
	A struct.Stuct who's pack() accepts either positional
	or name arguments, and who's unpack returns a named
	tuple supporing access by index or name.
	"""

	PACK_TYPES = "cbB?hHiIlLqQfdspP"
	PACK_FORMATS = {
		"B": "0x%02x",
		"?": "%d",
		"H": "0x%04x",
		"I": "0x%08x",
		"L": "0x%08x",
		"Q": "0x%016x",
	}

	def __init__(self, type_name, format, field_names):
		"""
		Crate a new NamedStruct. type_name is the name
		of tuple used in __str__ when result of unpack
		are printed. format is a struct.pack format.
		Field names are property names used by the namedtiple
		returned by unpack, and acceped as named args to pack.
		"""
		super(StructUnpacker, self).__init__(format)
		self.namedtuple = self._create_namedtuple(type_name, format, field_names)

	def _create_namedtuple(self, type_name, format, field_names):
		self.name = type_name
		format_types = [c for c in format if c in self.PACK_TYPES]
		assert len(format_types) == len(field_names)
		format_formats = ["%s" if not self.PACK_FORMATS.has_key(t) else self.PACK_FORMATS[t] for t in format_types]
		str_format = ", ".join("%s=%s" % el for el in zip(field_names, format_formats))

		class result(collections.namedtuple(type_name, field_names)):
			def __str__(self):
				return (type_name + "(" + str_format + ")") % self
		return result

	def pack(self, *args, **kwds):
		return super(StructUnpacker, self).pack(*self.namedtuple(*args, **kwds))

	def unpack(self, string):
		return self.namedtuple(*super(StructUnpacker, self).unpack(string))._asdict()

	def dump(self, result):
		return str(self.namedtuple(**result))

class RegexUnpacker(object):
	"""
	Fascade so python named regex have similar API
	to NamedStruct above.
	"""

	def __init__(self, type_name, regexpr):
		"""
		Create a new NamedRegex. the provided
		regexpr string should use named groupings.
		"""
		self.name = type_name
		self.regexpr = re.compile(regexpr)
		groupindex = dict(self.regexpr.groupindex.items())
		for n in range(1, self.regexpr.groups + 1):
			if n not in groupindex.values():
				groupindex["arg" + str(n)] = n
		groups = groupindex.keys()
		groups.sort(key=lambda el : groupindex[el])
		self.namedtuple = collections.namedtuple(type_name, groups)

	def unpack(self, string):
		return self.namedtuple(*self.regexpr.search(string).groups())._asdict()

	def dump(self, result):
		return str(self.namedtuple(**result))

class StandardAntHeaderUnpacker(object):

	name = "AntHeaderUnpacker"

	def unpack(self, string):
		(sync, length, msg_id) = struct.unpack("BBB", string[:3])
		# fixme extended messages
		return {"sync": sync, "length": length, "msg_id": msg_id, "data": string[3:length + 3]}

	def dump(self, message):
		return "ANT(0x%02x)" % message["msg_id"]

class DefaultUnpacker(object):

	name = "DefaultUnpacker"

	def unpack(self, string):
		return {"data": string.encode("hex")}

	def dump(self, message):
		return message["data"]

class UsbMonUnpacker(object):

	def __init__(self, name="UsbMonUnpack"):
		self.name = name
		self.re_out = RegexUnpacker("USB_BulkOut", r"(?P<packet_type>Bo):.*= (?P<data>(?:[0-9a-f]{1,8} ?)+)")
		self.re_in = RegexUnpacker("USB_BulkIn", r"(?P<packet_type>Bi):.*= (?P<data>(?:[0-9a-f]{1,8} ?)+)")

	def unpack(self, string):
		result = None
		if "Bo" in string and "=" in string:
			result = self.re_out.unpack(string)
		elif "Bi" in string and "=" in string:
			result = self.re_in.unpack(string)
		if result and result.has_key("data"):
			result["data"] = binascii.unhexlify(result["data"].replace(" ", ""))
		return result

	def dump(self, message):
		if message:
			return ">>" if message["packet_type"] == "Bo" else "<<"

class Disassembler(object):

	stackentry = collections.namedtuple("StackEntry", ["unpacker", "message"])
	protocols = []

	def disasm(self, data, stack):
		for (expr, unpacker) in self.protocols:
			val = False
			try: val = eval(expr)
			except IndexError: pass
			except AttributeError: pass
			except KeyError: pass
			if val:
				message = unpacker.unpack(data)
				if message is not None:
					stack.append(self.stackentry(unpacker, message))
					if message.has_key("data"):
						self.disasm(stack[-1].message["data"], stack)
						break
		return stack

	def dump(self, stack):
		indent = ""
		for entry in stack:
			if hasattr(entry.unpacker, "dump"):
				print indent + entry.unpacker.dump(entry.message),
		if stack: print

d = Disassembler()
d.protocols = [
	("len(stack) == 0", UsbMonUnpacker()),
	("len(stack) == 1", StandardAntHeaderUnpacker()),
]

for (function, msg_id, fmt, args) in ANT_ALL_FUNCTIONS:
	expr = "len(stack) == 2 and stack[0].message['packet_type'] == 'Bo' and stack[1].message['msg_id'] == 0x%x and stack[1].message['length'] == %d" % (msg_id, struct.calcsize(fmt))
	d.protocols.append((expr, StructUnpacker(function, fmt, args)))

for (function, msg_id, fmt, args) in ANT_ALL_CALLBACKS:
	expr = "len(stack) == 2 and stack[0].message['packet_type'] == 'Bi' and stack[1].message['msg_id'] == 0x%x and stack[1].message['length'] == %d" % (msg_id, struct.calcsize(fmt))
	d.protocols.append((expr, StructUnpacker(function, fmt, args)))

d.protocols.append(("len(stack) == 2", DefaultUnpacker()))

while True:
	line = sys.stdin.readline()
	if not line: break
	d.dump(d.disasm(line, []))
<commit_msg>formating of data params unpacked<commit_after>"""
Main source tree (AntDevice) can already serve a as protocol
disassembler at least ant api protocol level. This is as work
in progress to help parse the data payload. This codes pretty
ugly, just looking from something to do while i wait for gps
device to acutally be delivered.
"""

import sys
import binascii
import re
import struct
import collections

ANT_ALL_FUNCTIONS = [
    ("unassignChannel", 0x41, "<B", ["channelNumber"]),
    ("assignChannel", 0x42, "<BBB", ["channelNumber", "channelType", "networkNumber"]),
    ("assignChannel", 0x42, "<BBBB", ["channelNumber", "channelType", "networkNumber", "extendedAttrs"]),
    ("setChannelId", 0x51, "<BHBB", ["channelNumber", "deviceNumber", "deviceTypeId", "transType"]),
    ("setChannelPeriod", 0x43, "<BH", ["channelNumber", "messagePeriod"]),
    ("setChannelSearchTimeout", 0x44, "<BB", ["channelNumber", "searchTimeout"]),
    ("setChannelRfFreq", 0x45, "<BB", ["channelNumber", "rfFrequency"]),
    ("setNetworkKey", 0x46, "<BQ", ["networkNumber", "key"]),
    ("setTransmitPower", 0x47, "<xB", ["txPower"]),
    ("addChannelId", 0x59, "<BHBBB", ["channelNumber", "deviceNumber", "deviceTypeId", "transType","listIndex"]),
    ("configList", 0x5A, "<BB?", ["channelNumber", "listSize", "exclude"]),
    ("setChannelTxPower", 0x60, "<BB", ["channelNumber", "txPower"]),
    ("setLowPriorityChannelSearchTimeout", 0x63, "<BB", ["channelNumber", "searchTimeout"]),
    ("setSerialNumChannelId", 0x65, "<BBB", ["channelNumber", "deviceTypeId", "transType"]),
    ("rxExtMesgsEnable", 0x66, "<x?", ["enable"]),
    ("enableLed", 0x68, "<x?", ["enable"]),
    ("crystalEnable", 0x6D, "<x", []),
    ("libConfig", 0x6E, "<xB", ["libConfig"]),
    ("configFrequencyAgility", 0x70, "<BBBB", ["channelNumber", "freq1", "freq2", "freq3"]),
    ("setProximitySearch", 0x71, "<BB", ["channelNumber", "searchThresholdId"]),
    ("setChannelSearchPriority", 0x75, "<BB", ["channelNumber", "searchPriority"]),
    ("resetSystem", 0x4A, "<x", []),
    ("openChannel", 0x4B, "<B", ["channelNumber"]),
    ("closeChannel", 0x4C, "<B", ["channelNumber"]),
    ("openRxScanMode", 0x5B, "<x", []),
    ("requestMessage", 0x4D, "<BB", ["channelNumber", "messageId"]),
    ("sleepMessage", 0xC5, "<x", []),
    ("sendBroadcastData", 0x4E, "<B8s", ["channelNumber", "data"]),
    ("sendAcknowledgedData", 0x4F, "<B8s", ["channelNumber", "data"]),
    ("sendBurstTransferPacket", 0x50, "<B8s", ["channelNumber", "data"]),
    ("initCWTestMode", 0x53, "<x", []),
    ("setCwTestMode", 0x48, "<xBB", ["txPower", "rfFreq"]),
    ("sendExtBroadcastData", 0x5D, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("sendExtAcknowledgedData", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("sendExtBurstTransferPacket", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
]

ANT_ALL_CALLBACKS = [
    ("startupMessage", 0x6F, "<B", ["startupMesssage"]),
    ("serialErrorMessage", 0xAE, "<B", ["errorNumber"]),
    ("broadcastData", 0x4E, "<B8s", ["channelNumber", "data"]),
    ("acknowledgedData", 0x4F, "<B8s", ["channelNumber", "data"]),
    ("burstTransferPacket", 0x50, "<B8s", ["channelNumber", "data"]),
    ("channelEvent", 0x40, "<BBB", ["channelNumber", "messageId", "messageCode"]),
    ("channelStatus", 0x52, "<BB", ["channelNumber", "channelStatus"]),
    ("channelId", 0x51, "<BHBB", ["channelNumber", "deviceNumber", "deviceTypeId", "manId"]),
    ("antVersion", 0x3E, "<11s", ["version"]),
    ("capabilities", 0x54, "<BBBBBB", ["maxChannels", "maxNetworks", "standardOptions", "advancedOptions", "advancedOptions2", "reserved"]),
    ("serialNumber", 0x61, "<4s", ["serialNumber"]),
    ("extBroadcastData", 0x5D, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("extAcknowledgedData", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
    ("extBurstTransferPacket", 0x5E, "<BHBB8s", ["channelNumber", "deviceNumber", "deviceTypeId", "transType", "data"]),
]

class StructUnpacker(struct.Struct):
	"""
	A struct.Stuct who's pack() accepts either positional
	or name arguments, and who's unpack returns a named
	tuple supporing access by index or name.
	"""

	PACK_TYPES = "cbB?hHiIlLqQfdspP"
	PACK_FORMATS = {
		"B": "0x%02x",
		"?": "%d",
		"H": "0x%04x",
		"I": "0x%08x",
		"L": "0x%08x",
		"Q": "0x%016x",
	}

	def __init__(self, type_name, format, field_names):
		"""
		Crate a new NamedStruct. type_name is the name
		of tuple used in __str__ when result of unpack
		are printed. format is a struct.pack format.
		Field names are property names used by the namedtiple
		returned by unpack, and acceped as named args to pack.
		"""
		super(StructUnpacker, self).__init__(format)
		self.namedtuple = self._create_namedtuple(type_name, format, field_names)

	def _create_namedtuple(self, type_name, format, field_names):
		self.name = type_name
		format_types = [c for c in format if c in self.PACK_TYPES]
		assert len(format_types) == len(field_names)
		format_formats = ["%s" if not self.PACK_FORMATS.has_key(t) else self.PACK_FORMATS[t] for t in format_types]
		str_format = ", ".join("%s=%s" % el for el in zip(field_names, format_formats))

		class result(collections.namedtuple(type_name, field_names)):
			def __str__(self):
				kwds = self if not hasattr(self, "data") else self._replace(data=getattr(self, "data").encode("hex"))
				return (type_name + "(" + str_format + ")") % kwds
		return result

	def pack(self, *args, **kwds):
		return super(StructUnpacker, self).pack(*self.namedtuple(*args, **kwds))

	def unpack(self, string):
		return self.namedtuple(*super(StructUnpacker, self).unpack(string))._asdict()

	def dump(self, result):
		return str(self.namedtuple(**result))

class RegexUnpacker(object):
	"""
	Fascade so python named regex have similar API
	to NamedStruct above.
	"""

	def __init__(self, type_name, regexpr):
		"""
		Create a new NamedRegex. the provided
		regexpr string should use named groupings.
		"""
		self.name = type_name
		self.regexpr = re.compile(regexpr)
		groupindex = dict(self.regexpr.groupindex.items())
		for n in range(1, self.regexpr.groups + 1):
			if n not in groupindex.values():
				groupindex["arg" + str(n)] = n
		groups = groupindex.keys()
		groups.sort(key=lambda el : groupindex[el])
		self.namedtuple = collections.namedtuple(type_name, groups)

	def unpack(self, string):
		return self.namedtuple(*self.regexpr.search(string).groups())._asdict()

	def dump(self, result):
		return str(self.namedtuple(**result))

class StandardAntHeaderUnpacker(object):

	name = "AntHeaderUnpacker"

	def unpack(self, string):
		(sync, length, msg_id) = struct.unpack("BBB", string[:3])
		# fixme extended messages
		return {"sync": sync, "length": length, "msg_id": msg_id, "data": string[3:length + 3]}

	def dump(self, message):
		return "ANT(0x%02x)" % message["msg_id"]

class DefaultUnpacker(object):

	name = "DefaultUnpacker"

	def unpack(self, string):
		return {"data": string.encode("hex")}

	def dump(self, message):
		return message["data"]

class UsbMonUnpacker(object):

	def __init__(self, name="UsbMonUnpack"):
		self.name = name
		self.re_out = RegexUnpacker("USB_BulkOut", r"(?P<packet_type>Bo):.*= (?P<data>(?:[0-9a-f]{1,8} ?)+)")
		self.re_in = RegexUnpacker("USB_BulkIn", r"(?P<packet_type>Bi):.*= (?P<data>(?:[0-9a-f]{1,8} ?)+)")

	def unpack(self, string):
		result = None
		if "Bo" in string and "=" in string:
			result = self.re_out.unpack(string)
		elif "Bi" in string and "=" in string:
			result = self.re_in.unpack(string)
		if result and result.has_key("data"):
			result["data"] = binascii.unhexlify(result["data"].replace(" ", ""))
		return result

	def dump(self, message):
		if message:
			return ">>" if message["packet_type"] == "Bo" else "<<"

class Disassembler(object):

	stackentry = collections.namedtuple("StackEntry", ["unpacker", "message"])
	protocols = []

	def disasm(self, data, stack):
		for (expr, unpacker) in self.protocols:
			val = False
			try: val = eval(expr)
			except IndexError: pass
			except AttributeError: pass
			except KeyError: pass
			if val:
				message = unpacker.unpack(data)
				if message is not None:
					stack.append(self.stackentry(unpacker, message))
					if message.has_key("data"):
						self.disasm(stack[-1].message["data"], stack)
						break
		return stack

	def dump(self, stack):
		indent = ""
		for entry in stack:
			if hasattr(entry.unpacker, "dump"):
				print indent + entry.unpacker.dump(entry.message),
		if stack: print

d = Disassembler()
d.protocols = [
	("len(stack) == 0", UsbMonUnpacker()),
	("len(stack) == 1", StandardAntHeaderUnpacker()),
]

for (function, msg_id, fmt, args) in ANT_ALL_FUNCTIONS:
	expr = "len(stack) == 2 and stack[0].message['packet_type'] == 'Bo' and stack[1].message['msg_id'] == 0x%x and stack[1].message['length'] == %d" % (msg_id, struct.calcsize(fmt))
	d.protocols.append((expr, StructUnpacker(function, fmt, args)))

for (function, msg_id, fmt, args) in ANT_ALL_CALLBACKS:
	expr = "len(stack) == 2 and stack[0].message['packet_type'] == 'Bi' and stack[1].message['msg_id'] == 0x%x and stack[1].message['length'] == %d" % (msg_id, struct.calcsize(fmt))
	d.protocols.append((expr, StructUnpacker(function, fmt, args)))

d.protocols.append(("len(stack) == 2", DefaultUnpacker()))

while True:
	line = sys.stdin.readline()
	if not line: break
	d.dump(d.disasm(line, []))
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Asyncode Runtime - XML framework allowing developing internet
# applications without using programming languages.
# Copyright (C) 2008-2010  Adrian Kalbarczyk

# This program is free software: you can redistribute it and/or modify
# it under the terms of the version 3 of GNU General Public License as published by
# the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from ACR.utils.xmlextras import *
from ACR import acconfig
from ACR import components
from ACR.errors import *
from ACR.utils import getStorage,prepareVars,typesMap
from ACR.utils.interpreter import make_tree
from ACR.components import Object, List
import os,re

DEFINE="define"
SET="set"
COMMAND="command"
INHERITS="inherits"
IMPORT="import"

def parsePosts(nodes):
	if not nodes:
		return (None,None)
	ret={}
	postCount=0
	for i in nodes:
		attrs=i[1]
		typ=typesMap.get(attrs.get("type"),typesMap["default"])()
		if attrs.has_key("default"):
			typ.setDefault(make_tree(attrs["default"]))
			postCount+=1
		ret[attrs["name"]]=typ
	return (ret,postCount)

def parseInputs(nodes):
	if not nodes:
		return None
	ret=[]
	postCount=0
	for i in nodes:
		attrs=i[1]
		typ=typesMap.get(attrs.get("type","default"))()
		if attrs.has_key("default"):
			typ.setDefault(make_tree(attrs["default"]))
		ret.append({
			"name":attrs["name"],
			"type":typ
		})
	return ret

class View(object):
	def __init__(self, name, app):
		#All "static" computations should be here. Don't do it inside handle!
		#setting immutable because of setter
		self.immutable=False
		self.name="/".join(name)
		self.app=app
		self.path=os.path.join(app.viewsPath,*name)+".xml"
		#try:
		self.timestamp=os.stat(self.path).st_mtime
		tree=xml2tree(self.path, True)
		#TODO support more exception classes;
		#except Exception,e:
		#	self.immutable=True
		#	raise ViewNotFound("view '%s' not found"%(name))
		ns={}
		if not tree[1]:
			return
		#parses "xmlns:" attributes and extracts namespaces
		for i in tree[1]:
			if i.startswith("xmlns:"):
				key=i.split(":")[1]
				value=tree[1][i].split("/").pop().lower()
				ns[key]=value
		self.namespaces=ns
		#checks whether view inherits from another view
		try:
			self.parent=app.getView(filter(lambda x: not str.isspace(x) and len(x)!=0,tree[1]["inherits"].split("/")))[0]
		except:
			self.parent=None
		inputSchemas=[]
		conditions=[]
		actions=[]
		postSchemas=[]
		output=[]
		ACTIONS=[SET,DEFINE,IMPORT]
		for node in tree[2]:
			if type(node) is str:
				continue
			name=node[0]
			if name=="param":
				inputSchemas.append(node)
			elif name=="condition":
				conditions.append(node)
			elif name=="output":
				output.append(node)
			elif name=="post":
				postSchemas=filter(lambda x: type(x) is not str, node[2])
			elif name in ACTIONS:
				actions.append(node)
		self.conditions=self.parseConditions(conditions)
		self.actions=self.parseActions(actions)
		self.inputSchemas=parseInputs(inputSchemas) or []
		if self.parent and self.parent.inputSchemas:
			self.inputSchemas=self.parent.inputSchemas+self.inputSchemas
		self.postSchemas, self.postCount=parsePosts(postSchemas)
		self.output={}
		try:
			self.output["format"]=output[0][1]["format"]
		except: pass
		try:
			self.output["xsltfile"]=output[0][1]["xsltfile"]
		except: pass
		try:
			self.outputConfig=output[0][1]["config"]
		except:
			outputConfig="config"
		# TODO check if it is correct
		## output inheritance
		#if self.parent and self.parent.outputFormat:
		#		self.outputFormat=self.parent.outputFormat
		#		self.outputConfig=self.parent.outputConfig
		## posts inheritance
		#if self.parent and self.parent.posts:
		#	self.posts=self.parent.posts
		#if not self.actions:
		#	self.immutable=True
		#	return
		#if D: log.debug("Setting defaults for posts")
		#past here this object MUST be immutable
		self.immutable=True

	def parseConditions(self, a):
		ret=[]
		for i in a:
			attrs=i[1]
			ret.append({
				"name":attrs.get("name"),
				"value":make_tree(attrs.get("value") or "".join(i[2]).strip())
			})
		return ret

	def checkConditions(self, acenv):
		for i in self.conditions:
			if i["value"] and not execute(acenv, i["value"]):
				return False
		return True

	#def importAction(self,action):
	#	path=re.split("/*",action[1].get("path"))
	#	v=self.app.getView(path[:-1])[0]
	#	for a in v.actions:
	#		if a["name"]==path[-1]:
	#			ret.append(a)
	#			ret[-1]["name"]=action[1].get("name", None)
	#			break

	def parseAction(self,action):
		""" Gets tuple representation of action XML element and returns dict-based configuration """
		attrs=action[1]
		ns,cmd=NS2Tuple(attrs.get(COMMAND,"default"))
		params={}
		if ns:
			for attr in attrs:
				if attr.startswith(ns+":") and not attr==ns+cmd:
					params[attr.split(":").pop()]=prepareVars(action[1][attr])
		ret={
			"command":cmd,
			"params":params,
			"content":action[2]
		}
		if action[0]==DEFINE:
			ret["output"]=True
		return ret

	def parseActions(self,actions):
		def findAction(actions,name):
			if not name:
				return None
			i=len(actions)-1
			if i<=0:
				return None
			try:
				while not actions[i]["name"]==name:
					i-=1
				return i
			except:
				return None
			else:
				return len(actions)

		if self.parent:
			ret=self.parent.actions[:]
		else:
			ret=[]
		for action in actions:
			#if i[0]=="import":
			#	self.importAction(i[0])
			#	continue
			typ=action[0]
			attrs=action[1]
			ns,cmd=NS2Tuple(attrs.get(COMMAND,"default"))
			componentName=self.namespaces.get(ns,"default")
			o={
				"type":typ,#DEFINE or SET
				#"command":cmd,#command name
				"name":attrs.get("name",None),
				"component":componentName,
				"condition":make_tree(attrs.get("condition")),
				"default":make_tree(attrs.get("default")),
				"config":self.app.getComponent(componentName).parseAction(self.parseAction(action)),
			}

			# positions the action in the list of actions
			before=attrs.get("before")
			after=attrs.get("after")
			parentPos=findAction(ret,o["name"])
			if before:
				if before=='*':
					ret.insert(0, o)
					ret.pop(parentPos)
				else:
					try:
						ret.insert(findAction(ret,before),o)
					except:
						pass
			elif after:
				if after=='*':
					ret.append(o)
					ret.pop(parentPos)
				else:
					try:
						ret.insert(findAction(ret,after)+1,o)
					except:
						pass
			else:
				if parentPos:
					ret.pop(parentPos)
				ret.append(o)
		return ret

	def fillPosts(self,acenv):
		D=acenv.doDebug
		if D:
			acenv.debug("START fillPosts")
		if not self.postSchemas or not len(self.postSchemas):
			if D: acenv.debug("posts schema is empty. Returning 'True'.")
			return True
		if D:acenv.debug("postSchemas is %s",self.postSchemas)
		list=acenv.posts
		if not list or len(list)<self.postCount:
			#TODO normalize the Error messages!
			raise Error("Not enough post fields")
		postSchemas=self.postSchemas
		try:
			for i in postSchemas:
				value=list.get(i)
				typ=postSchemas[i]
				typ.set(value)
				acenv.requestStorage[i]=typ.get(acenv)
		except Error,e:
			if e.name=="NotValidValue":
				raise Error("NotValidValue", "Value of %s is invalid"%(i))

	def fillInputs(self,acenv):
		D=acenv.doDebug
		if D: acenv.debug("START fillInputs")
		inputSchemas=self.inputSchemas
		if D: acenv.debug("inputSchemas are: %s",inputSchemas)
		if not inputSchemas or not len(inputSchemas):
			if D: acenv.debug("list of inputs is empty. Returning 'True'.")
			return True
		list=acenv.inputs
		if D: acenv.debug("inputs are: %s",list)
		for i in inputSchemas:
			typ=i["type"]
			try:
				typ.set(list.pop(0))
			except:
				pass
			acenv.requestStorage[i["name"]]=typ.get(acenv)
		if D:
			acenv.debug("RS is: %s",acenv.requestStorage)
			acenv.debug("END fillInputs")

	def generate(self,acenv):
		D=acenv.doDebug
		try:
			self.inputSchemas
		except:# inputs is undefined
			acenv.generations.append(("object",{"type":"view","name":self.name},None))
			self.transform(acenv)
			return
		#if D: acenv.debug("Executing with env=%s",acenv)
		self.fillInputs(acenv)
		self.fillPosts(acenv)
		acenv.requestStorage["__lang__"]=acenv.lang
		#print "rs"
		#print acenv.requestStorage
		#print "actions"
		#print self.actions
		for action in self.actions:
			if D: acenv.info("define name='%s'",action["name"])
			if action["condition"] and not action["condition"].execute(acenv):
				#print "condition not meet %s"%(str(action["condition"].tree))
				#print action["name"]
				if D: acenv.warning("Condition is not meet")
				if action["type"]==SET:
					if D: acenv.warning("Set condition is not meet.")
					ns,name=NS2Tuple(action["name"],"::")
					default=action.get("default")
					if default:
						getStorage(acenv,ns or "rs")[name]=default.execute(acenv)
				continue
			component=self.app.getComponent(action["component"])
			#object or list
			generation=component.generate(acenv,action["config"])
			##print "generation"
			##print generation._value
			##print acenv.requestStorage
			if not generation:
				raise Error("ComponentError","Component did not return proper value. Please contact component author.")
			if not action["name"]:
					continue
			if action["type"]==DEFINE:
				if D: acenv.info("Executing action=%s",action)
				generation.name=action["name"]
				generation.view=self.name
				acenv.generations[action["name"]]=generation
			elif action["type"]==SET:
				if D: acenv.info("Executing SET=%s",action)
				ns,name=NS2Tuple(action["name"],"::")
				getStorage(acenv,ns or "rs")[name]=generation

		try:
			acenv.output["format"]=self.output["format"]
		except:
			pass
		try:
			acenv.output["xsltfile"]=self.output["xsltfile"]
		except:
			pass

	def isUpToDate(self):
		return self.timestamp >= os.stat(self.path).st_mtime

	def __setattr__(self, name, val):
		if name!="immutable" and self.immutable:
			#if D: log.error("%s is read only",name)
			raise Exception("PropertyImmutable")
		self.__dict__[name]=val
<commit_msg>Wrong input type raises GlobalError<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Asyncode Runtime - XML framework allowing developing internet
# applications without using programming languages.
# Copyright (C) 2008-2010  Adrian Kalbarczyk

# This program is free software: you can redistribute it and/or modify
# it under the terms of the version 3 of GNU General Public License as published by
# the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from ACR.utils.xmlextras import *
from ACR import acconfig
from ACR import components
from ACR.errors import *
from ACR.utils import getStorage,prepareVars,typesMap
from ACR.utils.interpreter import make_tree
from ACR.components import Object, List
import os,re

DEFINE="define"
SET="set"
COMMAND="command"
INHERITS="inherits"
IMPORT="import"

def parsePosts(nodes):
	if not nodes:
		return (None,None)
	ret={}
	postCount=0
	for i in nodes:
		attrs=i[1]
		typ=typesMap.get(attrs.get("type"),typesMap["default"])()
		if attrs.has_key("default"):
			typ.setDefault(make_tree(attrs["default"]))
			postCount+=1
		ret[attrs["name"]]=typ
	return (ret,postCount)

def parseInputs(nodes):
	if not nodes:
		return None
	ret=[]
	postCount=0
	for i in nodes:
		attrs=i[1]
		try:
			typ=typesMap.get(attrs.get("type","default"))()
		except TypeError:
			raise Error("WrongInputTypeName","Input type '%s' is not supported."%attrs.get("type","default"))
		if attrs.has_key("default"):
			typ.setDefault(make_tree(attrs["default"]))
		ret.append({
			"name":attrs["name"],
			"type":typ
		})
	return ret

class View(object):
	def __init__(self, name, app):
		#All "static" computations should be here. Don't do it inside handle!
		#setting immutable because of setter
		self.immutable=False
		self.name="/".join(name)
		self.app=app
		self.path=os.path.join(app.viewsPath,*name)+".xml"
		#try:
		self.timestamp=os.stat(self.path).st_mtime
		tree=xml2tree(self.path, True)
		#TODO support more exception classes;
		#except Exception,e:
		#	self.immutable=True
		#	raise ViewNotFound("view '%s' not found"%(name))
		ns={}
		if not tree[1]:
			return
		#parses "xmlns:" attributes and extracts namespaces
		for i in tree[1]:
			if i.startswith("xmlns:"):
				key=i.split(":")[1]
				value=tree[1][i].split("/").pop().lower()
				ns[key]=value
		self.namespaces=ns
		#checks whether view inherits from another view
		try:
			self.parent=app.getView(filter(lambda x: not str.isspace(x) and len(x)!=0,tree[1]["inherits"].split("/")))[0]
		except:
			self.parent=None
		inputSchemas=[]
		conditions=[]
		actions=[]
		postSchemas=[]
		output=[]
		ACTIONS=[SET,DEFINE,IMPORT]
		for node in tree[2]:
			if type(node) is str:
				continue
			name=node[0]
			if name=="param":
				inputSchemas.append(node)
			elif name=="condition":
				conditions.append(node)
			elif name=="output":
				output.append(node)
			elif name=="post":
				postSchemas=filter(lambda x: type(x) is not str, node[2])
			elif name in ACTIONS:
				actions.append(node)
		self.conditions=self.parseConditions(conditions)
		self.actions=self.parseActions(actions)
		self.inputSchemas=parseInputs(inputSchemas) or []
		if self.parent and self.parent.inputSchemas:
			self.inputSchemas=self.parent.inputSchemas+self.inputSchemas
		self.postSchemas, self.postCount=parsePosts(postSchemas)
		self.output={}
		try:
			self.output["format"]=output[0][1]["format"]
		except: pass
		try:
			self.output["xsltfile"]=output[0][1]["xsltfile"]
		except: pass
		try:
			self.outputConfig=output[0][1]["config"]
		except:
			outputConfig="config"
		# TODO check if it is correct
		## output inheritance
		#if self.parent and self.parent.outputFormat:
		#		self.outputFormat=self.parent.outputFormat
		#		self.outputConfig=self.parent.outputConfig
		## posts inheritance
		#if self.parent and self.parent.posts:
		#	self.posts=self.parent.posts
		#if not self.actions:
		#	self.immutable=True
		#	return
		#if D: log.debug("Setting defaults for posts")
		#past here this object MUST be immutable
		self.immutable=True

	def parseConditions(self, a):
		ret=[]
		for i in a:
			attrs=i[1]
			ret.append({
				"name":attrs.get("name"),
				"value":make_tree(attrs.get("value") or "".join(i[2]).strip())
			})
		return ret

	def checkConditions(self, acenv):
		for i in self.conditions:
			if i["value"] and not execute(acenv, i["value"]):
				return False
		return True

	#def importAction(self,action):
	#	path=re.split("/*",action[1].get("path"))
	#	v=self.app.getView(path[:-1])[0]
	#	for a in v.actions:
	#		if a["name"]==path[-1]:
	#			ret.append(a)
	#			ret[-1]["name"]=action[1].get("name", None)
	#			break

	def parseAction(self,action):
		""" Gets tuple representation of action XML element and returns dict-based configuration """
		attrs=action[1]
		ns,cmd=NS2Tuple(attrs.get(COMMAND,"default"))
		params={}
		if ns:
			for attr in attrs:
				if attr.startswith(ns+":") and not attr==ns+cmd:
					params[attr.split(":").pop()]=prepareVars(action[1][attr])
		ret={
			"command":cmd,
			"params":params,
			"content":action[2]
		}
		if action[0]==DEFINE:
			ret["output"]=True
		return ret

	def parseActions(self,actions):
		def findAction(actions,name):
			if not name:
				return None
			i=len(actions)-1
			if i<=0:
				return None
			try:
				while not actions[i]["name"]==name:
					i-=1
				return i
			except:
				return None
			else:
				return len(actions)

		if self.parent:
			ret=self.parent.actions[:]
		else:
			ret=[]
		for action in actions:
			#if i[0]=="import":
			#	self.importAction(i[0])
			#	continue
			typ=action[0]
			attrs=action[1]
			ns,cmd=NS2Tuple(attrs.get(COMMAND,"default"))
			componentName=self.namespaces.get(ns,"default")
			o={
				"type":typ,#DEFINE or SET
				#"command":cmd,#command name
				"name":attrs.get("name",None),
				"component":componentName,
				"condition":make_tree(attrs.get("condition")),
				"default":make_tree(attrs.get("default")),
				"config":self.app.getComponent(componentName).parseAction(self.parseAction(action)),
			}

			# positions the action in the list of actions
			before=attrs.get("before")
			after=attrs.get("after")
			parentPos=findAction(ret,o["name"])
			if before:
				if before=='*':
					ret.insert(0, o)
					ret.pop(parentPos)
				else:
					try:
						ret.insert(findAction(ret,before),o)
					except:
						pass
			elif after:
				if after=='*':
					ret.append(o)
					ret.pop(parentPos)
				else:
					try:
						ret.insert(findAction(ret,after)+1,o)
					except:
						pass
			else:
				if parentPos:
					ret.pop(parentPos)
				ret.append(o)
		return ret

	def fillPosts(self,acenv):
		D=acenv.doDebug
		if D:
			acenv.debug("START fillPosts")
		if not self.postSchemas or not len(self.postSchemas):
			if D: acenv.debug("posts schema is empty. Returning 'True'.")
			return True
		if D:acenv.debug("postSchemas is %s",self.postSchemas)
		list=acenv.posts
		if not list or len(list)<self.postCount:
			#TODO normalize the Error messages!
			raise Error("Not enough post fields")
		postSchemas=self.postSchemas
		try:
			for i in postSchemas:
				value=list.get(i)
				typ=postSchemas[i]
				typ.set(value)
				acenv.requestStorage[i]=typ.get(acenv)
		except Error,e:
			if e.name=="NotValidValue":
				raise Error("NotValidValue", "Value of %s is invalid"%(i))

	def fillInputs(self,acenv):
		D=acenv.doDebug
		if D: acenv.debug("START fillInputs")
		inputSchemas=self.inputSchemas
		if D: acenv.debug("inputSchemas are: %s",inputSchemas)
		if not inputSchemas or not len(inputSchemas):
			if D: acenv.debug("list of inputs is empty. Returning 'True'.")
			return True
		list=acenv.inputs
		if D: acenv.debug("inputs are: %s",list)
		for i in inputSchemas:
			typ=i["type"]
			try:
				typ.set(list.pop(0))
			except:
				pass
			acenv.requestStorage[i["name"]]=typ.get(acenv)
		if D:
			acenv.debug("RS is: %s",acenv.requestStorage)
			acenv.debug("END fillInputs")

	def generate(self,acenv):
		D=acenv.doDebug
		try:
			self.inputSchemas
		except:# inputs is undefined
			acenv.generations.append(("object",{"type":"view","name":self.name},None))
			self.transform(acenv)
			return
		#if D: acenv.debug("Executing with env=%s",acenv)
		self.fillInputs(acenv)
		self.fillPosts(acenv)
		acenv.requestStorage["__lang__"]=acenv.lang
		#print "rs"
		#print acenv.requestStorage
		#print "actions"
		#print self.actions
		for action in self.actions:
			if D: acenv.info("define name='%s'",action["name"])
			if action["condition"] and not action["condition"].execute(acenv):
				#print "condition not meet %s"%(str(action["condition"].tree))
				#print action["name"]
				if D: acenv.warning("Condition is not meet")
				if action["type"]==SET:
					if D: acenv.warning("Set condition is not meet.")
					ns,name=NS2Tuple(action["name"],"::")
					default=action.get("default")
					if default:
						getStorage(acenv,ns or "rs")[name]=default.execute(acenv)
				continue
			component=self.app.getComponent(action["component"])
			#object or list
			generation=component.generate(acenv,action["config"])
			##print "generation"
			##print generation._value
			##print acenv.requestStorage
			if not generation:
				raise Error("ComponentError","Component did not return proper value. Please contact component author.")
			if not action["name"]:
					continue
			if action["type"]==DEFINE:
				if D: acenv.info("Executing action=%s",action)
				generation.name=action["name"]
				generation.view=self.name
				acenv.generations[action["name"]]=generation
			elif action["type"]==SET:
				if D: acenv.info("Executing SET=%s",action)
				ns,name=NS2Tuple(action["name"],"::")
				getStorage(acenv,ns or "rs")[name]=generation

		try:
			acenv.output["format"]=self.output["format"]
		except:
			pass
		try:
			acenv.output["xsltfile"]=self.output["xsltfile"]
		except:
			pass

	def isUpToDate(self):
		return self.timestamp >= os.stat(self.path).st_mtime

	def __setattr__(self, name, val):
		if name!="immutable" and self.immutable:
			#if D: log.error("%s is read only",name)
			raise Exception("PropertyImmutable")
		self.__dict__[name]=val
<|endoftext|>


<commit_before>#!/usr/bin/python2.7

import os
import sys
import zlib
import base64
import socket
import os.path
import argparse
from datetime import datetime

import debug
import module
import config as CFG
from poetsocket import *

__version__ = '0.4.4'

POSH_PROMPT = 'posh > '
FAKEOK = """HTTP/1.1 200 OK\r
Date: Tue, 19 Mar 2013 22:12:25 GMT\r
Server: Apache\r
X-Powered-By: PHP/5.3.10-1ubuntu3.2\r
Content-Length: 364\r
Content-Type: text/plain\r
\r
body{background-color:#f0f0f2;margin:0;padding:0;font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif}div{width:600px;margin:5em auto;padding:50px;background-color:#fff;border-radius:1em}a:link,a:visited{color:#38488f;text-decoration:none}@media (max-width:700px){body{background-color:#fff}div{width:auto;margin:0 auto;border-radius:0;padding:1em}}"""

class PoetSocketServer(PoetSocket):
    def __init__(self, port):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.s.bind(('', port))
        self.s.listen(1)

    def accept(self):
        return self.s.accept()

class PoetServer(object):
    """Core server functionality.

    Implements control shell, and necessary helper functions.

    Attributes:
        s: socket instance for initial client connection
        conn: socket instance for actual client communication
        cmds: list of supported control shell commands
    """

    def __init__(self, s):
        self.s = s
        self.conn = None
        self.builtins = ['exit', 'help']
        # exists so modules can stop server (used by selfdestruct)
        self.continue_ = True

    def start(self):
        """Poet server control shell."""

        debug.info('Entering control shell')
        self.conn = PoetSocket(self.s.accept()[0])
        print 'Welcome to posh, the Poet Shell!'
        print 'Running `help\' will give you a list of supported commands.'
        while True:
            try:
                found = False
                argv = raw_input(POSH_PROMPT).split()

                #
                # builtins
                #

                if argv == []:
                    continue
                if argv[0] == 'exit':
                    break
                elif argv[0] == 'help':
                    found = True
                    print 'Commands:\n  {}'.format('\n  '.join(sorted(self.builtins + module.server_commands.keys())))

                #
                # modules
                #

                # try to find command in registered modules
                for cmd, func in module.server_commands.iteritems():
                    if argv[0] == cmd:
                        found = True
                        try:
                            func(self, argv)
                        except Exception as e:
                            self.info(str(e.args))

                # see comment above for self.continue_ for why this is here
                if not self.continue_:
                    return

                if not found:
                    self.info('{}: command not found'.format(argv[0]))
            except KeyboardInterrupt:
                print
                continue
            except EOFError:
                print
                break
        self.conn.send('fin')
        debug.info('Exiting control shell')

    def info(self, msg):
        print 'posh : {}'.format(msg)

    def generic(self, req, write_flag=False, write_file=None):
        """Abstraction layer for exchanging with client and writing to file.

        Args:
            req: command to send to client
            write_flag: whether client response should be written
            write_file: optional filename to use for file
        """

        resp = self.conn.exchange(req)
        # TODO: this hardcoding is bad, should be some generic way to see
        # if response should be decompressed. maybe a list of all keywords
        # which cause a compressed response to come back
        if req == 'recon':
            resp = zlib.decompress(resp)
        print resp
        if write_flag:
            self.write(resp, req.split()[0], write_file)

    def write(self, response, prefix, write_file=None):
        """Write to server archive.

        Args:
            response: data to write
            prefix: directory to write file to (usually named after command
                    executed)
            write_file: optional filename to use for file
        """

        ts = datetime.now().strftime('%Y%m%d%M%S')
        out_ts_dir = '{}/{}'.format(CFG.ARCHIVE_DIR, ts[:len('yyyymmdd')])
        out_prefix_dir = '{}/{}'.format(out_ts_dir, prefix)

        # create filename to write to
        if write_file:
            chunks = write_file.split('.')
            # separate the file extension from the file name, default to .txt
            ext = '.{}'.format('.'.join(chunks[1:])) if chunks[1:] else '.txt'
            outfile = '{}/{}-{}{}'.format(out_prefix_dir, chunks[0], ts, ext)
        else:
            outfile = '{}/{}-{}.txt'.format(out_prefix_dir, prefix, ts)

        # create directories if they don't exist
        if not os.path.isdir(CFG.ARCHIVE_DIR):
            os.mkdir(CFG.ARCHIVE_DIR)
        if not os.path.isdir(out_ts_dir):
            os.mkdir(out_ts_dir)
        if not os.path.isdir(out_prefix_dir):
            os.mkdir(out_prefix_dir)

        # if file already exists, append unique digit to the end
        if os.path.exists(outfile):
            count = 1
            orig_outfile = outfile
            outfile = orig_outfile + '.{}'.format(count)
            while os.path.exists(outfile):
                outfile = orig_outfile + '.{}'.format(count)
                count += 1

        with open(outfile, 'w') as f:
            f.write(response)
            print 'posh : {} written to {}'.format(prefix, outfile)

    def exec_preproc(self, inp):
        """Parse posh `exec' command line.

        Args:
            inp: raw `exec' command line

        Returns:
            Tuple suitable for expansion into as self.generic() parameters.
        """

        tmp = inp.split()
        write_file = None
        write_flag = tmp[1] == '-o'
        if write_flag:
            if '"' not in tmp[2]:
                write_file = tmp[2]
                del tmp[2]
            del tmp[1]
        tmp = ' '.join(tmp)
        return tmp, write_flag, write_file

def get_args():
    """ Parse arguments and return dictionary. """

    parser = argparse.ArgumentParser()
    parser.add_argument('-p', '--port')
    parser.add_argument('-v', '--version', action='store_true',
                        help='prints the Poet version number and exits')
    return parser.parse_args()

def print_header():
    """ Prints big ASCII logo and other info. """

    print """
                          _
        ____  ____  ___  / /_
       / __ \/ __ \/ _ \/ __/
      / /_/ / /_/ /  __/ /
     / .___/\____/\___/\__/     v{}
    /_/
""".format(__version__)

def die(msg=None):
    if msg:
        debug.err(msg)
    debug.err('Poet server terminated')
    sys.exit(0)

def authenticate(ping):
    """Verify that the client is in fact connecting by checking the request
    path and the auth token contained in the cookie.

    Args:
        ping: http request sent from client (string)

    Returns:
        None: client authenticated successfully
        str: the reason authentication failed
    """

    if ping.startswith('GET /style.css HTTP/1.1'):
        if 'Cookie: c={};'.format(base64.b64encode(CFG.AUTH)) in ping:
            return None
        else:
            return 'AUTH TOKEN'
    else:
        return 'REQUEST'

def drop_privs():
    try:
        new_uid = int(os.getenv('SUDO_UID'))
        new_gid = int(os.getenv('SUDO_GID'))
    except TypeError:
        # they were running directly from a root user and didn't have
        # sudo env variables
        print """[!] WARNING: Couldn't drop privileges! To avoid this error, run from a non-root user.
    You may also use sudo, from a non-root user. Continue? (y/n)""",
        if raw_input().lower()[0] == 'y':
            return
        die()

    debug.info('Dropping privileges to uid: {}, gid: {}'.format(new_uid,
                                                                new_gid))

    # drop group before user, because otherwise you're not privileged enough
    # to drop group
    os.setgroups([])
    os.setregid(new_gid, new_gid)
    os.setreuid(new_uid, new_uid)

    # check to make sure we can't re-escalate
    try:
        os.seteuid(0)
        print '[!] WARNING: Failed to drop privileges! Continue? (y/n)',
        if raw_input().lower()[0] != 'y':
            die()
    except OSError:
        return

def main():
    args = get_args()
    if args.version:
        print 'Poet version {}'.format(__version__)
        sys.exit(0)
    print_header()
    PORT = int(args.port) if args.port else 443
    try:
        s = PoetSocketServer(PORT)
    except socket.error as e:
        if e.errno == 13:
            die('You need to be root!')
    if os.geteuid() == 0:
        drop_privs()
    debug.info('Poet server started on port: {}'.format(PORT))
    module.load_modules()
    while True:
        try:
            conn, addr = s.accept()
        except KeyboardInterrupt:
            die()
        conntime = datetime.now().strftime(debug.DATE_FMT)
        ping = conn.recv(SIZE)
        if not ping:
            die('Socket error: {}'.format(e.message))
        auth_err = authenticate(ping)
        if auth_err:
            print '[!] ({}) Connected By: {} -> INVALID! ({})'.format(conntime, addr, auth_err)
            conn.close()
        else:
            print '[+] ({}) Connected By: {} -> VALID'.format(conntime, addr)
            conn.send(FAKEOK)
            conn.close()
            try:
                PoetServer(s).start()
                break
            except Exception as e:
                print e
                die('Fatal error: {}'.format(e.message))
    die()

if __name__ == '__main__':
    main()
<commit_msg>Dude, it's a hashtable<commit_after>#!/usr/bin/python2.7

import os
import sys
import zlib
import base64
import socket
import os.path
import argparse
from datetime import datetime

import debug
import module
import config as CFG
from poetsocket import *

__version__ = '0.4.4'

POSH_PROMPT = 'posh > '
FAKEOK = """HTTP/1.1 200 OK\r
Date: Tue, 19 Mar 2013 22:12:25 GMT\r
Server: Apache\r
X-Powered-By: PHP/5.3.10-1ubuntu3.2\r
Content-Length: 364\r
Content-Type: text/plain\r
\r
body{background-color:#f0f0f2;margin:0;padding:0;font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif}div{width:600px;margin:5em auto;padding:50px;background-color:#fff;border-radius:1em}a:link,a:visited{color:#38488f;text-decoration:none}@media (max-width:700px){body{background-color:#fff}div{width:auto;margin:0 auto;border-radius:0;padding:1em}}"""

class PoetSocketServer(PoetSocket):
    def __init__(self, port):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.s.bind(('', port))
        self.s.listen(1)

    def accept(self):
        return self.s.accept()

class PoetServer(object):
    """Core server functionality.

    Implements control shell, and necessary helper functions.

    Attributes:
        s: socket instance for initial client connection
        conn: socket instance for actual client communication
        cmds: list of supported control shell commands
    """

    def __init__(self, s):
        self.s = s
        self.conn = None
        self.builtins = {
            'exit': self._builtin_exit,
            'help': self._builtin_help
        }
        # exists so modules can stop server (used by selfdestruct and exit)
        self.continue_ = True

    def start(self):
        """Poet server control shell."""

        debug.info('Entering control shell')
        self.conn = PoetSocket(self.s.accept()[0])
        print 'Welcome to posh, the Poet Shell!'
        print 'Running `help\' will give you a list of supported commands.'
        while True:
            try:
                # found = False
                argv = raw_input(POSH_PROMPT).split()
                if not argv:
                    continue

                if argv[0] in self.builtins:
                    self.builtins[argv[0]](argv)
                elif argv[0] in module.server_commands:
                    try:
                        module.server_commands[argv[0]](self, argv)
                    except Exception as e:
                        self.info(str(e.args))
                else:
                    self.info('{}: command not found'.format(argv[0]))

                # see comment above for self.continue_ for why this is here
                if not self.continue_:
                    break
            except KeyboardInterrupt:
                print
                continue
            except EOFError:
                print
                break
        self.conn.send('fin')
        debug.info('Exiting control shell')

    def info(self, msg):
        print 'posh : {}'.format(msg)

    def generic(self, req, write_flag=False, write_file=None):
        """Abstraction layer for exchanging with client and writing to file.

        Args:
            req: command to send to client
            write_flag: whether client response should be written
            write_file: optional filename to use for file
        """

        resp = self.conn.exchange(req)
        # TODO: this hardcoding is bad, should be some generic way to see
        # if response should be decompressed. maybe a list of all keywords
        # which cause a compressed response to come back
        if req == 'recon':
            resp = zlib.decompress(resp)
        print resp
        if write_flag:
            self.write(resp, req.split()[0], write_file)

    def write(self, response, prefix, write_file=None):
        """Write to server archive.

        Args:
            response: data to write
            prefix: directory to write file to (usually named after command
                    executed)
            write_file: optional filename to use for file
        """

        ts = datetime.now().strftime('%Y%m%d%M%S')
        out_ts_dir = '{}/{}'.format(CFG.ARCHIVE_DIR, ts[:len('yyyymmdd')])
        out_prefix_dir = '{}/{}'.format(out_ts_dir, prefix)

        # create filename to write to
        if write_file:
            chunks = write_file.split('.')
            # separate the file extension from the file name, default to .txt
            ext = '.{}'.format('.'.join(chunks[1:])) if chunks[1:] else '.txt'
            outfile = '{}/{}-{}{}'.format(out_prefix_dir, chunks[0], ts, ext)
        else:
            outfile = '{}/{}-{}.txt'.format(out_prefix_dir, prefix, ts)

        # create directories if they don't exist
        if not os.path.isdir(CFG.ARCHIVE_DIR):
            os.mkdir(CFG.ARCHIVE_DIR)
        if not os.path.isdir(out_ts_dir):
            os.mkdir(out_ts_dir)
        if not os.path.isdir(out_prefix_dir):
            os.mkdir(out_prefix_dir)

        # if file already exists, append unique digit to the end
        if os.path.exists(outfile):
            count = 1
            orig_outfile = outfile
            outfile = orig_outfile + '.{}'.format(count)
            while os.path.exists(outfile):
                outfile = orig_outfile + '.{}'.format(count)
                count += 1

        with open(outfile, 'w') as f:
            f.write(response)
            print 'posh : {} written to {}'.format(prefix, outfile)

    def exec_preproc(self, inp):
        """Parse posh `exec' command line.

        Args:
            inp: raw `exec' command line

        Returns:
            Tuple suitable for expansion into as self.generic() parameters.
        """

        tmp = inp.split()
        write_file = None
        write_flag = tmp[1] == '-o'
        if write_flag:
            if '"' not in tmp[2]:
                write_file = tmp[2]
                del tmp[2]
            del tmp[1]
        tmp = ' '.join(tmp)
        return tmp, write_flag, write_file

    def _builtin_exit(self, argv):
        self.continue_ = False

    def _builtin_help(self, argv):
        print 'Builtins:\n  {}'.format('\n  '.join(sorted(self.builtins.keys())))
        print
        print 'Commands:\n  {}'.format('\n  '.join(sorted(module.server_commands.keys())))

def get_args():
    """ Parse arguments and return dictionary. """

    parser = argparse.ArgumentParser()
    parser.add_argument('-p', '--port')
    parser.add_argument('-v', '--version', action='store_true',
                        help='prints the Poet version number and exits')
    return parser.parse_args()

def print_header():
    """ Prints big ASCII logo and other info. """

    print """
                          _
        ____  ____  ___  / /_
       / __ \/ __ \/ _ \/ __/
      / /_/ / /_/ /  __/ /
     / .___/\____/\___/\__/     v{}
    /_/
""".format(__version__)

def die(msg=None):
    if msg:
        debug.err(msg)
    debug.err('Poet server terminated')
    sys.exit(0)

def authenticate(ping):
    """Verify that the client is in fact connecting by checking the request
    path and the auth token contained in the cookie.

    Args:
        ping: http request sent from client (string)

    Returns:
        None: client authenticated successfully
        str: the reason authentication failed
    """

    if ping.startswith('GET /style.css HTTP/1.1'):
        if 'Cookie: c={};'.format(base64.b64encode(CFG.AUTH)) in ping:
            return None
        else:
            return 'AUTH TOKEN'
    else:
        return 'REQUEST'

def drop_privs():
    try:
        new_uid = int(os.getenv('SUDO_UID'))
        new_gid = int(os.getenv('SUDO_GID'))
    except TypeError:
        # they were running directly from a root user and didn't have
        # sudo env variables
        print """[!] WARNING: Couldn't drop privileges! To avoid this error, run from a non-root user.
    You may also use sudo, from a non-root user. Continue? (y/n)""",
        if raw_input().lower()[0] == 'y':
            return
        die()

    debug.info('Dropping privileges to uid: {}, gid: {}'.format(new_uid,
                                                                new_gid))

    # drop group before user, because otherwise you're not privileged enough
    # to drop group
    os.setgroups([])
    os.setregid(new_gid, new_gid)
    os.setreuid(new_uid, new_uid)

    # check to make sure we can't re-escalate
    try:
        os.seteuid(0)
        print '[!] WARNING: Failed to drop privileges! Continue? (y/n)',
        if raw_input().lower()[0] != 'y':
            die()
    except OSError:
        return

def main():
    args = get_args()
    if args.version:
        print 'Poet version {}'.format(__version__)
        sys.exit(0)
    print_header()
    PORT = int(args.port) if args.port else 443
    try:
        s = PoetSocketServer(PORT)
    except socket.error as e:
        if e.errno == 13:
            die('You need to be root!')
    if os.geteuid() == 0:
        drop_privs()
    debug.info('Poet server started on port: {}'.format(PORT))
    module.load_modules()
    while True:
        try:
            conn, addr = s.accept()
        except KeyboardInterrupt:
            die()
        conntime = datetime.now().strftime(debug.DATE_FMT)
        ping = conn.recv(SIZE)
        if not ping:
            die('Socket error: {}'.format(e.message))
        auth_err = authenticate(ping)
        if auth_err:
            print '[!] ({}) Connected By: {} -> INVALID! ({})'.format(conntime, addr, auth_err)
            conn.close()
        else:
            print '[+] ({}) Connected By: {} -> VALID'.format(conntime, addr)
            conn.send(FAKEOK)
            conn.close()
            try:
                PoetServer(s).start()
                break
            except Exception as e:
                print e
                die('Fatal error: {}'.format(e.message))
    die()

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


<commit_before>from os import path
from gusto import *
from firedrake import (as_vector, PeriodicIntervalMesh,
                       SpatialCoordinate, ExtrudedMesh, FunctionSpace, Function,
                       conditional, sqrt)
from firedrake.slope_limiter.vertex_based_limiter import VertexBasedLimiter
from netCDF4 import Dataset

# This setup creates a sharp bubble of warm air in a vertical slice
# This bubble is then advected by a prescribed advection scheme
# If the limiter is working, the advection should have produced
# no new maxima or minima. Advection is a solid body rotation.

def setup_limiters(dirname):

    dt = 0.1
    Ld = 10.
    tmax = 2
    m = PeriodicIntervalMesh(20, Ld)
    mesh = ExtrudedMesh(m, layers=20, layer_height=(Ld/20))
    output = OutputParameters(dirname=dirname, dumpfreq=1, dumplist=['u', 'chemical', 'moisture'])
    parameters = CompressibleParameters()
    timestepping = TimesteppingParameters(dt=dt, maxk=4, maxi=1)
    fieldlist = ['u', 'rho', 'theta', 'chemical', 'moisture']
    diagnostic_fields = []
    state = State(mesh, vertical_degree=1, horizontal_degree=1,
                  family="CG",
                  timestepping=timestepping,
                  output=output,
                  parameters=parameters,
                  fieldlist=fieldlist,
                  diagnostic_fields=diagnostic_fields)

    x, z = SpatialCoordinate(state.mesh)

    Vr = state.spaces("DG")
    Vt = state.spaces("HDiv_v")
    Vpsi = FunctionSpace(state.mesh, "CG", 2)

    u = state.fields("u", dump=True)
    chemical = state.fields("chemical", Vr, dump=True)
    moisture = state.fields("moisture", Vt, dump=True)

    x_lower = 2 * Ld / 5
    x_upper = 3 * Ld / 5
    z_lower = 6 * Ld / 10
    z_upper = 8 * Ld / 10
    bubble_expr_1 = conditional(x > x_lower,
                                conditional(x < x_upper,
                                            conditional(z > z_lower,
                                                        conditional(z < z_upper, 1.0, 0.0),
                                                        0.0),
                                            0.0),
                                0.0)

    bubble_expr_2 = conditional(x > z_lower,
                                conditional(x < z_upper,
                                            conditional(z > x_lower,
                                                        conditional(z < x_upper, 1.0, 0.0),
                                                        0.0),
                                            0.0),
                                0.0)

    chemical.assign(1.0)
    moisture.assign(280.)
    chem_pert_1 = Function(Vr).interpolate(bubble_expr_1)
    chem_pert_2 = Function(Vr).interpolate(bubble_expr_2)
    moist_pert_1 = Function(Vt).interpolate(bubble_expr_1)
    moist_pert_2 = Function(Vt).interpolate(bubble_expr_2)

    chemical.assign(chemical + chem_pert_1 + chem_pert_2)
    moisture.assign(moisture + moist_pert_1 + moist_pert_2)

    # set up solid body rotation for advection
    xc = Ld / 2
    zc = Ld / 2
    r = sqrt((x - xc) ** 2 + (z - zc) ** 2)
    umax = 0.1
    omega = umax * sqrt(2) / Ld
    r_out = 9 * Ld / 20
    r_in = 2 * Ld / 5
    A = omega * r_in / (2 * (r_in - r_out))
    B = - omega * r_in * r_out / (r_in - r_out)
    C = omega * r_in ** 2 * r_out / (r_in - r_out) / 2
    psi_expr = conditional(r < r_in,
                           omega * r ** 2 / 2,
                           conditional(r < r_out,
                                       A * r ** 2 + B * r + C,
                                       A * r_out ** 2 + B * r_out + C))
    psi = Function(Vpsi).interpolate(psi_expr)

    gradperp = lambda v: as_vector([-v.dx(1), v.dx(0)])
    u.project(gradperp(psi))

    state.initialise([('u', u),
                      ('chemical', chemical),
                      ('moisture', moisture)])

    # set up advection schemes
    dg_opts = EmbeddedDGOptions()
    chemeqn = AdvectionEquation(state, Vr, equation_form="advective")
    moisteqn = EmbeddedDGAdvection(state, Vt, equation_form="advective", options=dg_opts)

    # build advection dictionary
    advected_fields = []
    advected_fields.append(('chemical', SSPRK3(state, chemical, chemeqn, limiter=VertexBasedLimiter(Vr))))
    advected_fields.append(('moisture', SSPRK3(state, moisture, moisteqn, limiter=ThetaLimiter(Vt))))

    # build time stepper
    stepper = AdvectionDiffusion(state, advected_fields)

    return stepper, tmax

def run_limiters(dirname):

    stepper, tmax = setup_limiters(dirname)
    stepper.run(t=0, tmax=tmax)
    # print(stepper.state.fields('moisture').dat.data[:])
    return

def test_limiters(tmpdir):

    dirname = str(tmpdir)
    run_limiters(dirname)
    filename = path.join(dirname, "diagnostics.nc")
    data = Dataset(filename, "r")

    chem_data = data.groups["chemical"]
    max_chem = chem_data.variables["max"]
    min_chem = chem_data.variables["min"]

    moist_data = data.groups["moisture"]
    max_moist = moist_data.variables["max"]
    min_moist = moist_data.variables["min"]

    tolerance = 0.1

    # check that maxima and minima do not exceed previous maxima and minima
    # however provide a small amount of tolerance
    assert max_moist[-1] <= max_moist[0] + (max_moist[0] - min_moist[0]) * tolerance
    assert min_moist[-1] >= min_moist[0] - (max_moist[0] - min_moist[0]) * tolerance
    assert max_chem[-1] <= max_chem[0] + (max_chem[0] - min_chem[0]) * tolerance
    assert min_chem[-1] >= min_chem[0] - (max_chem[0] - min_chem[0]) * tolerance
<commit_msg>update the test for the limiter<commit_after>from os import path
from gusto import *
from firedrake import (as_vector, PeriodicIntervalMesh, interval, FiniteElement, pi,
                       SpatialCoordinate, ExtrudedMesh, FunctionSpace, Function,
                       conditional, sqrt, BrokenElement, TensorProductElement)
from firedrake.slope_limiter.vertex_based_limiter import VertexBasedLimiter
from netCDF4 import Dataset

# This setup creates a sharp bubble of warm air in a vertical slice
# This bubble is then advected by a prescribed advection scheme
# If the limiter is working, the advection should have produced
# no new maxima or minima. Advection is a solid body rotation.

def setup_limiters(dirname):

    dt = 0.01
    Ld = 1.
    tmax = 0.2
    rotations = 0.1
    m = PeriodicIntervalMesh(20, Ld)
    mesh = ExtrudedMesh(m, layers=20, layer_height=(Ld/20))
    output = OutputParameters(dirname=dirname, dumpfreq=1, dumplist=['u', 'chemical', 'moisture_higher', 'moisture_lower'])
    parameters = CompressibleParameters()
    timestepping = TimesteppingParameters(dt=dt, maxk=4, maxi=1)
    fieldlist = ['u', 'rho', 'theta', 'chemical', 'moisture_higher', 'moisture_lower']
    diagnostic_fields = []
    state = State(mesh, vertical_degree=1, horizontal_degree=1,
                  family="CG",
                  timestepping=timestepping,
                  output=output,
                  parameters=parameters,
                  fieldlist=fieldlist,
                  diagnostic_fields=diagnostic_fields)

    x, z = SpatialCoordinate(mesh)

    Vr = state.spaces("DG")
    Vt = state.spaces("HDiv_v")
    Vpsi = FunctionSpace(mesh, "CG", 2)

    cell = mesh._base_mesh.ufl_cell().cellname()
    DG0_element = FiniteElement("DG", cell, 0)
    CG1_element = FiniteElement("CG", interval, 1)
    Vt0_element = TensorProductElement(DG0_element, CG1_element)
    Vt0 = FunctionSpace(mesh, Vt0_element)
    Vt0_brok = FunctionSpace(mesh, BrokenElement(Vt0_element))
    VCG1 = FunctionSpace(mesh, "CG", 1)

    u = state.fields("u", dump=True)
    chemical = state.fields("chemical", Vr, dump=True)
    moisture_higher = state.fields("moisture_higher", Vt, dump=True)
    moisture_lower = state.fields("moisture_lower", Vt0, dump=True)

    x_lower = 2 * Ld / 5
    x_upper = 3 * Ld / 5
    z_lower = 6 * Ld / 10
    z_upper = 8 * Ld / 10
    bubble_expr_1 = conditional(x > x_lower,
                                conditional(x < x_upper,
                                            conditional(z > z_lower,
                                                        conditional(z < z_upper, 1.0, 0.0),
                                                        0.0),
                                            0.0),
                                0.0)

    bubble_expr_2 = conditional(x > z_lower,
                                conditional(x < z_upper,
                                            conditional(z > x_lower,
                                                        conditional(z < x_upper, 1.0, 0.0),
                                                        0.0),
                                            0.0),
                                0.0)

    chemical.assign(1.0)
    moisture_higher.assign(280.)
    chem_pert_1 = Function(Vr).interpolate(bubble_expr_1)
    chem_pert_2 = Function(Vr).interpolate(bubble_expr_2)
    moist_h_pert_1 = Function(Vt).interpolate(bubble_expr_1)
    moist_h_pert_2 = Function(Vt).interpolate(bubble_expr_2)
    moist_l_pert_1 = Function(Vt0).interpolate(bubble_expr_1)
    moist_l_pert_2 = Function(Vt0).interpolate(bubble_expr_2)

    chemical.assign(chemical + chem_pert_1 + chem_pert_2)
    moisture_higher.assign(moisture_higher + moist_h_pert_1 + moist_h_pert_2)
    moisture_lower.assign(moisture_lower + moist_l_pert_1 + moist_l_pert_2)

    # set up solid body rotation for advection
    # we do this slightly complicated stream function to make the velocity 0 at edges
    # thus we avoid odd effects at boundaries
    xc = Ld / 2
    zc = Ld / 2
    r = sqrt((x - xc) ** 2 + (z - zc) ** 2)
    omega = rotations * 2 * pi / tmax
    r_out = 9 * Ld / 20
    r_in = 2 * Ld / 5
    A = omega * r_in / (2 * (r_in - r_out))
    B = - omega * r_in * r_out / (r_in - r_out)
    C = omega * r_in ** 2 * r_out / (r_in - r_out) / 2
    psi_expr = conditional(r < r_in,
                           omega * r ** 2 / 2,
                           conditional(r < r_out,
                                       A * r ** 2 + B * r + C,
                                       A * r_out ** 2 + B * r_out + C))
    psi = Function(Vpsi).interpolate(psi_expr)

    gradperp = lambda v: as_vector([-v.dx(1), v.dx(0)])
    u.project(gradperp(psi))

    state.initialise([('u', u),
                      ('chemical', chemical),
                      ('moisture_higher', moisture_higher),
                      ('moisture_lower', moisture_lower)])

    # set up advection schemes
    dg_opts = EmbeddedDGOptions()
    recovered_opts = RecoveredOptions(embedding_space=Vr,
                                      recovered_space=VCG1,
                                      broken_space=Vt0_brok,
                                      boundary_method=Boundary_Method.dynamics)

    chemeqn = AdvectionEquation(state, Vr, equation_form="advective")
    moisteqn_higher = EmbeddedDGAdvection(state, Vt, equation_form="advective", options=dg_opts)
    moisteqn_lower = EmbeddedDGAdvection(state, Vt0, equation_form="advective", options=recovered_opts)

    # build advection dictionary
    advected_fields = []
    advected_fields.append(('chemical', SSPRK3(state, chemical, chemeqn, limiter=VertexBasedLimiter(Vr))))
    advected_fields.append(('moisture_higher', SSPRK3(state, moisture_higher, moisteqn_higher, limiter=ThetaLimiter(Vt))))
    advected_fields.append(('moisture_lower', SSPRK3(state, moisture_lower, moisteqn_lower, limiter=VertexBasedLimiter(Vr))))

    # build time stepper
    stepper = AdvectionDiffusion(state, advected_fields)

    return stepper, tmax

def run_limiters(dirname):

    stepper, tmax = setup_limiters(dirname)
    stepper.run(t=0, tmax=tmax)
    # print(stepper.state.fields('moisture').dat.data[:])
    return

def test_limiters(tmpdir):

    dirname = str(tmpdir)
    run_limiters(dirname)
    filename = path.join(dirname, "diagnostics.nc")
    data = Dataset(filename, "r")

    chem_data = data.groups["chemical"]
    max_chem = chem_data.variables["max"]
    min_chem = chem_data.variables["min"]

    moist_h_data = data.groups["moisture_higher"]
    max_moist_h = moist_h_data.variables["max"]
    min_moist_h = moist_h_data.variables["min"]

    moist_l_data = data.groups["moisture_lower"]
    max_moist_l = moist_l_data.variables["max"]
    min_moist_l = moist_l_data.variables["min"]

    tolerance = 1e-8

    # check that maxima and minima do not exceed previous maxima and minima
    # however provide a small amount of tolerance
    assert max_chem[-1] <= max_chem[0] + (max_chem[0] - min_chem[0]) * tolerance
    assert min_chem[-1] >= min_chem[0] - (max_chem[0] - min_chem[0]) * tolerance
    assert max_moist_l[-1] <= max_moist_l[0] + (max_moist_l[0] - min_moist_l[0]) * tolerance
    assert min_moist_l[-1] >= min_moist_l[0] - (max_moist_l[0] - min_moist_l[0]) * tolerance
    assert max_moist_h[-1] <= max_moist_h[0] + (max_moist_h[0] - min_moist_h[0]) * tolerance
    assert min_moist_h[-1] >= min_moist_h[0] - (max_moist_h[0] - min_moist_h[0]) * tolerance
<|endoftext|>


<commit_before>import six
import types
import collections

from .log import get_logger
from .input import Input
from . import target

logger = get_logger()

class Task:

    tasks = []

    def __init__(self, *args, **kwargs):
        global current_task
        current_task = self

        inputs = self.get_inputs()
        input_values = self.get_input_values(inputs, args, kwargs)
        # Set all values on class instance
        for key, value in input_values:
            setattr(self, key, value)
        # Register args and kwargs as an attribute on the class. Might be useful
        self.input_values = input_values
        self.input_args = tuple(value for key, value in input_values)

        self.user_run = self.run

        # Add custom modifications to output()
        self.user_outputs = self.outputs
        # cache outputs
        global current_task
        current_task = self
        cached_outputs = self.user_outputs()
        current_task = None

        def outputs(self):
            return cached_outputs

        self.outputs = types.MethodType(outputs, self)

        # Add custom modifications to run()
        def run(self):
            logger.info('RUNNING {}'.format(self))
            self.user_run()
            out = self.outputs()
            if not isinstance(out, collections.Iterable):
                out = [out]
            for o in out:
                if not o.exists():
                    raise RuntimeError('Output {} not created after running task!'.format(o))

            logger.info('FINISHED {}'.format(self))

        self.run = types.MethodType(run, self)

        self.input_args = tuple(value for key, value in input_values)

        current_task = None

        self.__class__.tasks.append(self)

    def __repr__(self):
        result = []
        for k, w in self.input_values:
            result.append('{}={}'.format(k, repr(w)))

        return self.__class__.__name__ + '(' + ', '.join(result) + ')'

    def inputs(self):
        return self.input_args

    def outputs(self):
        pass

    def run(self):
        pass

    @classmethod
    def get_inputs(cls):
        inputs = []
        for input_name in dir(cls):
            input_obj = getattr(cls, input_name)
            if not isinstance(input_obj, Input):
                continue

            inputs.append((input_name, input_obj))

        inputs.sort(key=lambda t: t[1]._counter)
        return inputs

    @classmethod
    def get_input_values(cls, inputs, args, kwargs):
        result = {}

        inputs_dict = dict(inputs)

        # positional arguments
        positional_inputs = [(n, p) for n, p in inputs]
        for i, arg in enumerate(args):
            if i >= len(positional_inputs):
                raise ValueError()
            input_name, input_obj = positional_inputs[i]
            result[input_name] = arg

        # optional arguments
        for input_name, arg in six.iteritems(kwargs):
            if input_name in result:
                raise ValueError()
            if input_name not in inputs_dict:
                raise ValueError()
            result[input_name] = arg

        # substitute defaults
        for input_name, input_obj in inputs:
            if input_name not in result:
                if input_obj.default is None:
                    raise ValueError()
                result[input_name] = input_obj.default

        return [(input_name, result[input_name]) for input_name, input_obj in inputs]

    def __hash__(self):
        return hash(self.input_args)

    def __eq__(self, other):
        return repr(self) == repr(other)

current_task = None

def get_current_task():
    global current_task
    return current_task

<commit_msg>Update if Task code is modified<commit_after>import six
import types
import collections
import inspect

from .log import get_logger
from .input import Input
from . import target

logger = get_logger()

class Task:

    tasks = []

    def __init__(self, *args, **kwargs):
        global current_task
        current_task = self

        inputs = self.get_inputs()
        input_values = self.get_input_values(inputs, args, kwargs)
        # Set all values on class instance
        for key, value in input_values:
            setattr(self, key, value)
        # Register args and kwargs as an attribute on the class. Might be useful
        self.input_values = input_values
        self.input_args = tuple(value for key, value in input_values)

        self.user_run = self.run

        # Add custom modifications to output()
        self.user_outputs = self.outputs
        # cache outputs
        global current_task
        current_task = self
        cached_outputs = self.user_outputs()
        current_task = None

        def outputs(self):
            return cached_outputs

        self.outputs = types.MethodType(outputs, self)

        # Add custom modifications to run()
        def run(self):
            logger.info('RUNNING {}'.format(self))
            self.user_run()
            out = self.outputs()
            if not isinstance(out, collections.Iterable):
                out = [out]
            for o in out:
                if not o.exists():
                    raise RuntimeError('Output {} not created after running task!'.format(o))

            logger.info('FINISHED {}'.format(self))

        self.run = types.MethodType(run, self)

        self.input_args = tuple(value for key, value in input_values)

        current_task = None

        self.__class__.tasks.append(self)

    def __repr__(self):
        result = []
        for k, w in self.input_values:
            result.append('{}={}'.format(k, repr(w)))

        return self.__class__.__name__ + '(' + ', '.join(result) + ')'

    def inputs(self):
        return self.input_args

    def outputs(self):
        pass

    def run(self):
        pass

    @classmethod
    def get_inputs(cls):
        inputs = []
        for input_name in dir(cls):
            input_obj = getattr(cls, input_name)
            if not isinstance(input_obj, Input):
                continue

            inputs.append((input_name, input_obj))

        inputs.sort(key=lambda t: t[1]._counter)
        return inputs

    @classmethod
    def get_input_values(cls, inputs, args, kwargs):
        result = {}

        inputs_dict = dict(inputs)

        # positional arguments
        positional_inputs = [(n, p) for n, p in inputs]
        for i, arg in enumerate(args):
            if i >= len(positional_inputs):
                raise ValueError()
            input_name, input_obj = positional_inputs[i]
            result[input_name] = arg

        # optional arguments
        for input_name, arg in six.iteritems(kwargs):
            if input_name in result:
                raise ValueError()
            if input_name not in inputs_dict:
                raise ValueError()
            result[input_name] = arg

        # substitute defaults
        for input_name, input_obj in inputs:
            if input_name not in result:
                if input_obj.default is None:
                    raise ValueError()
                result[input_name] = input_obj.default

        return [(input_name, result[input_name]) for input_name, input_obj in inputs]

    def __hash__(self):
        return hash((self.input_args,
                     '\n'.join(inspect.getsourcelines(self.user_outputs)[0]),
                     '\n'.join(inspect.getsourcelines(self.user_run)[0]),
                   ))

    def __eq__(self, other):
        return repr(self) == repr(other)

current_task = None

def get_current_task():
    global current_task
    return current_task

<|endoftext|>