← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 1845: 1. Add yade.system module containing most startup things

 

------------------------------------------------------------
revno: 1845
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Thu 2009-12-03 00:01:36 +0100
message:
  1. Add yade.system module containing most startup things
  2. yade-trunk-py usable now; startup is _much_ faster than the c++ main :-) (lazy linkage?). If everything works well, the c++ main will be deprecated soon (though still functional)
added:
  py/system.py
modified:
  core/main/main.py.in
  core/main/pyboot.cpp
  gui/py/PythonUI_rc.py
  py/SConscript
  py/yadeWrapper/yadeWrapper.cpp


--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription.
=== modified file 'core/main/main.py.in'
--- core/main/main.py.in	2009-12-01 22:24:00 +0000
+++ core/main/main.py.in	2009-12-02 23:01:36 +0000
@@ -1,4 +1,5 @@
 #!/usr/bin/python
+# encoding: utf-8
 # syntax:python
 
 import sys,ctypes
@@ -22,7 +23,7 @@
 
 # find what is our version, based on argv[0]
 # should be improved
-import sys,re,os.path
+import sys,re,os,os.path
 m=re.match('(.*)/bin/yade(-.*)-py',sys.argv[0])
 if not m: raise RuntimeError("Unable to find prefix and yade version from argv[0]=='%s'."%sys.argv[0])
 prefix,suffix=m.group(1),m.group(2)
@@ -30,6 +31,9 @@
 pluginDirs=[libDir+dir for dir in ('','/plugins','/gui','/extra') if os.path.exists(libDir+dir)]
 sys.path.append(libDir+'/py')
 
+# this works, cool!
+## os.environ['OMP_NUM_THREADS']=str(1)
+
 # now we can import yade's c++ modules just fine
 import yade.boot
 yade.boot.initialize(pluginDirs,True)
@@ -57,15 +61,15 @@
 	if arg.endswith('.xml') or arg.endswith('.xml.bz2'): runtime.simulation=arg
 	elif arg.endswith('.py'): runtime.script=arg
 
-#
-# this fills __builtins__ with wrapped types and proxy classes; it could be factored out, though
-#
-execfile(prefix+'/lib/yade'+suffix+'/gui/PythonUI_rc.py')
-
 try:
 	import yade.qt
 	yade.qt.Controller()
 except ImportError: pass
+#
+# this fills __builtins__ with wrapped types and proxy classes; it could be factored out, though
+#
+execfile(prefix+'/lib/yade'+suffix+'/gui/PythonUI_rc.py')
+
 
 #setupPythonRuntime()
 

=== modified file 'core/main/pyboot.cpp'
--- core/main/pyboot.cpp	2009-12-01 11:02:55 +0000
+++ core/main/pyboot.cpp	2009-12-02 23:01:36 +0000
@@ -42,20 +42,11 @@
 		localLogger->setLevel(getenv("YADE_DEBUG")?debugLevel:warnLevel);
 	#endif
 
-	#if defined(YADE_OPENMP) || defined(YADE_OPENGL)
-		#ifdef LOG4CXX
-			LOG_ERROR("Yade compiled with openmp/opengl. Using python main will likely crash as soone as an ostream is used.")
-		#else
-			// avoid log4cxx-less LOG_ERROR, since it uses cerr, which crashes due to libsctc++ (?) issue.
-			fprintf(stderr,"ERROR: Yade compiled with openmp/opengl. Using python main will likely crash as soone as an ostream is used.\n");
-		#endif
-	#endif
-
 	PyEval_InitThreads();
 
 	Omega& O(Omega::instance());
 	O.init();
-	O.origArgv=NULL; O.origArgc=0;
+	O.origArgv=NULL; O.origArgc=0; // not needed, anyway
 	O.initTemps();
 	#ifdef YADE_DEBUG
 		if(gdb){

=== modified file 'gui/py/PythonUI_rc.py'
--- gui/py/PythonUI_rc.py	2009-12-01 14:56:39 +0000
+++ gui/py/PythonUI_rc.py	2009-12-02 23:01:36 +0000
@@ -4,125 +4,17 @@
 yade.runtime must have already been populated from within c++."""
 
 import sys
-sys.excepthook=sys.__excepthook__ # apport on ubuntu overrides this, we don't need it
-# sys.path.insert(0,runtime.prefix+'/lib/yade'+runtime.suffix+'/extra')
-
 from math import *
 from miniWm3Wrap import *
 from yade.wrapper import *
 from yade._customConverters import *
 from yade import runtime
 from yade import utils
-__builtins__.O=Omega()
-sys.exit=O.exitNoBacktrace
-
-### direct object creation through automatic wrapper functions
-def listChildClassesRecursive(base):
-	ret=set(O.childClasses(base)); ret2=set()
-	for bb in ret:
-		ret2|=listChildClassesRecursive(bb)
-	return ret | ret2
-
-# not sure whether __builtins__ is the right place?
-_proxyNamespace=__builtins__.__dict__
-# all classes that we want to handle at this point
-_allSerializables=set(listChildClassesRecursive('Serializable'))
-# classes that cannot be instantiated in python directly, and will have no properties generated for them
-_noPropsClasses=set(['InteractionContainer','BodyContainer','Functor','Engine','Dispatcher'])
-# classes that have special wrappers; only the most-bottom ones, with their names as it is in c++
-_pyRootClasses=set([
-	'StandAloneEngine','DeusExMachina','InteractingGeometry','BoundingVolume','InteractionGeometry','InteractionPhysics','FileGenerator',
-	'BoundingVolumeFunctor','InteractionGeometryFunctor','InteractionPhysicsFunctor','ConstitutiveLaw']+
-	(['GeometricalModelEngineUnit','InteractingGeometryEngineUnit','GeometricalModel'] if 'shape' in runtime.features else [])+(['PhysicalParameters','PhysicalActionApplierUnit','PhysicalActionDamperUnit','StateEngineUnit'] if 'physpar' in runtime.features else ['Material','State'])
-	# childless classes
-	+['BoundingVolumeDispatcher','InteractionGeometryDispatcher','InteractionPhysicsDispatcher','ConstitutiveLawDispatcher','InteractionDispatchers','ParallelEngine']
-)
-
-_proxiedClasses=set()
-
-
-if 1:
-	# create types for all classes that yade defines: first those deriving from some root classes
-	for root in _pyRootClasses:
-		try:
-			rootType=yade.wrapper.__dict__[root]
-		except KeyError:
-			print 'WARNING: class %s not defined'%root
-		for p in listChildClassesRecursive(root):
-			_proxyNamespace[p]=type(p,(rootType,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
-			_proxiedClasses.add(p)
-		# inject wrapped class itself into _proxyNamespace
-		_proxyNamespace[root]=rootType
-	# create types for classes that derive just from Serializable
-	for p in _allSerializables-_proxiedClasses-_pyRootClasses:
-		_proxyNamespace[p]=type(p,(Serializable,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
-	## NOTE: this will not work if the object is returned from c++; seems to be more confusing than doing any good; disabling for now.
-	if 0:
-		# create class properties for yade serializable attributes, i.e. access object['attribute'] as object.attribute
-		for c in _allSerializables-_noPropsClasses:
-			cls=eval(c) # ugly: create instance; better lookup some namespace (builtins? globals?)
-			for k in cls().keys(): # must be instantiated so that attributes can be retrieved
-				setattr(cls,k,property(lambda self,__k_=k:self.__getitem__(__k_),lambda self,val,__k_=k:self.__setitem__(__k_,val)))
-else:
-	# old code, can be removed at some point
-	for root in _pyRootClasses:
-		for p in listChildClassesRecursive(root):
-			_proxyNamespace[p]=lambda __r_=root,__p_=p,**kw : yade.wrapper.__dict__[__r_](__p_,**kw)
-			_proxiedClasses.add(p)
-	# wrap classes that don't derive from any specific root class, have no proxy and need it
-	for p in _allSerializables-_proxiedClasses-_pyRootClasses:
-		_proxyNamespace[p]=lambda __p_=p,**kw: yade.wrapper.Serializable(__p_,**kw)
-### end wrappers
-
-#### HANDLE RENAMED CLASSES ####
-# if old class name is used, the new object is constructed and a warning is issued about old name being used
-# keep chronologically ordered, oldest first; script/rename-class.py appends at the end
-renamed={
-	'CpmPhysDamageColorizer':'CpmStateUpdater', # renamed 10.10.2009
-	'GLDraw_Dem3DofGeom_FacetSphere':'Gl1_Dem3DofGeom_FacetSphere', # renamed 15.11.2009
-	'PeriodicInsertionSortCollider':'InsertionSortCollider',	# integrated 25.11.2009
-	'BoundingVolumeMetaEngine':'BoundingVolumeDispatcher', # Tue Dec  1 14:28:29 2009, vaclav@flux
-	'BoundingVolumeEngineUnit':'BoundingVolumeFunctor', # Tue Dec  1 14:39:53 2009, vaclav@flux
-	'InteractionGeometryMetaEngine':'InteractionGeometryDispatcher', # Tue Dec  1 14:40:36 2009, vaclav@flux
-	'InteractionPhysicsMetaEngine':'InteractionPhysicsDispatcher', # Tue Dec  1 14:40:53 2009, vaclav@flux
-	'InteractionPhysicsEngineUnit':'InteractionPhysicsFunctor', # Tue Dec  1 14:41:19 2009, vaclav@flux
-	'InteractionGeometryEngineUnit':'InteractionGeometryFunctor', # Tue Dec  1 14:41:56 2009, vaclav@flux
-	### END_RENAMED_CLASSES_LIST ### (do not delete this line; scripts/rename-class.py uses it
-}
-
-for oldName in renamed.keys():
-	class warnWrap:
-		def __init__(self,_old,_new):
-			# assert(_proxyNamespace.has_key(_new))
-			self.old,self.new=_old,_new
-		def __call__(self,*args,**kw):
-			import warnings; warnings.warn("Class `%s' was renamed to (or replaced by) `%s', update your code!"%(self.old,self.new),DeprecationWarning,stacklevel=3);
-			return _proxyNamespace[self.new](*args,**kw)
-	_proxyNamespace[oldName]=warnWrap(oldName,renamed[oldName])
-
-
-
-# python2.4 workaround (so that quit() works as it does in 2.5)
-if not callable(__builtins__.quit):
-	def _quit(): import sys; sys.exit(0)
-	__builtins__.quit=_quit
-
-def cleanup():
-	try:
-		#import yade.qt, time
-		import yade._qt
-		if yade._qt.isActive(): yade._qt.close();
-		#yade.qt.close()
-		#while True: time.sleep(.1) # wait to be killed
-	except ImportError: pass
-
-
-## run the TCP server
-import yade.PythonTCPServer
-srv=yade.PythonTCPServer.GenericTCPServer(handler=yade.PythonTCPServer.PythonConsoleSocketEmulator,title='TCP python prompt',cookie=True,minPort=9000)
-yade.runtime.cookie=srv.server.cookie
-info=yade.PythonTCPServer.GenericTCPServer(handler=yade.PythonTCPServer.InfoSocketProvider,title='TCP info provider',cookie=False,minPort=21000)
-sys.stdout.flush()
+
+import yade.system
+yade.system.setExitHandlers()
+yade.system.injectCtors()
+yade.system.runServers()
 
 
 if not runtime.__dict__.has_key('noSession'):
@@ -175,9 +67,10 @@
 			# http://lists.ipython.scipy.org/pipermail/ipython-user/2008-September/005839.html
 			import IPython.ipapi
 			IPython.ipapi.get().IP.atexit_operations()
-	except SystemExit:
-		cleanup()
-	finally:
-		cleanup()
+			O.exitNoBacktrace()
+	except SystemExit: pass
+		#cleanup()
+	finally: pass
+		#cleanup()
 
 	

=== modified file 'py/SConscript'
--- py/SConscript	2009-12-01 14:22:18 +0000
+++ py/SConscript	2009-12-02 23:01:36 +0000
@@ -27,6 +27,7 @@
 	env.File('linterpolation.py'),
 	env.File('timing.py'),
 	env.File('pack.py'),
+	env.File('system.py'),
 	env.File('export.py'),
 	env.File('post2d.py'),
 	env.SharedLibrary('wrapper',['yadeWrapper/yadeWrapper.cpp'],SHLIBPREFIX='',LIBS=['PythonUI']+linkPlugins(['Shop','BoundingVolumeDispatcher','InteractionGeometryDispatcher','InteractionPhysicsDispatcher','ConstitutiveLawDispatcher','InteractionDispatchers','ParallelEngine','Clump','STLImporter',]+(['GeometricalModelMetaEngine','InteractingGeometryMetaEngine',] if 'shape' in env['features'] else [])+(['StateMetaEngine',] if 'physpar' in env['features'] else []))),

=== added file 'py/system.py'
--- py/system.py	1970-01-01 00:00:00 +0000
+++ py/system.py	2009-12-02 23:01:36 +0000
@@ -0,0 +1,112 @@
+# coding: utf-8
+# 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+
+"""
+Functions for accessing yade's internals; only used internally.
+"""
+import sys
+from yade import wrapper
+from yade._customConverters import *
+from yade import runtime
+__builtins__['O']=wrapper.Omega()
+
+def childClasses(base):
+	"""Recursively enumerate classes deriving from given base (as string). Returns set."""
+	ret=set(O.childClassesNonrecursive(base)); ret2=set()
+	for bb in ret:
+		ret2|=childClasses(bb)
+	return ret | ret2
+
+_allSerializables=childClasses('Serializable')
+# classes that cannot be instantiated in python directly, and will have no properties generated for them
+_noPropsClasses=set(['InteractionContainer','BodyContainer','Functor','Engine','Dispatcher'])
+# classes that have special wrappers; only the most-bottom ones, with their names as it is in c++
+_pyRootClasses=set([
+	'StandAloneEngine','DeusExMachina','InteractingGeometry','BoundingVolume','InteractionGeometry','InteractionPhysics','FileGenerator',
+	'BoundingVolumeFunctor','InteractionGeometryFunctor','InteractionPhysicsFunctor','ConstitutiveLaw','Material','State']
+	# childless classes
+	+['BoundingVolumeDispatcher','InteractionGeometryDispatcher','InteractionPhysicsDispatcher','ConstitutiveLawDispatcher','InteractionDispatchers','ParallelEngine']
+)
+## set of classes for which the proxies were created
+_proxiedClasses=set()
+
+## deprecated classes
+# if old class name is used, the new object is constructed and a warning is issued about old name being used
+# keep chronologically ordered, oldest first; script/rename-class.py appends at the end
+_deprecated={
+	'CpmPhysDamageColorizer':'CpmStateUpdater', # renamed 10.10.2009
+	'GLDraw_Dem3DofGeom_FacetSphere':'Gl1_Dem3DofGeom_FacetSphere', # renamed 15.11.2009
+	'PeriodicInsertionSortCollider':'InsertionSortCollider',	# integrated 25.11.2009
+	'BoundingVolumeMetaEngine':'BoundingVolumeDispatcher', # Tue Dec  1 14:28:29 2009, vaclav@flux
+	'BoundingVolumeEngineUnit':'BoundingVolumeFunctor', # Tue Dec  1 14:39:53 2009, vaclav@flux
+	'InteractionGeometryMetaEngine':'InteractionGeometryDispatcher', # Tue Dec  1 14:40:36 2009, vaclav@flux
+	'InteractionPhysicsMetaEngine':'InteractionPhysicsDispatcher', # Tue Dec  1 14:40:53 2009, vaclav@flux
+	'InteractionPhysicsEngineUnit':'InteractionPhysicsFunctor', # Tue Dec  1 14:41:19 2009, vaclav@flux
+	'InteractionGeometryEngineUnit':'InteractionGeometryFunctor', # Tue Dec  1 14:41:56 2009, vaclav@flux
+	### END_RENAMED_CLASSES_LIST ### (do not delete this line; scripts/rename-class.py uses it
+}
+
+
+def injectCtors(proxyNamespace=__builtins__):
+	"""Input wrapped classes as well as proxies for their derived types into the __builtins__ namespace. Should be invoked at yade startup.
+	
+	Root classes are those that are directly wrapped by boost::python. These are only imported to proxyNamespace.
+
+	Derived classes (from these root classes) are faked by creating a callable which invokes appropriate root class constructor with the derived class parameter and passes remaining arguments to it.
+
+	Classes that are neither root nor derived are exposed via callable object that constructs a Serializable of given type and passes the parameters.
+	"""
+	# classes derived from wrappers (but not from Serializable directly)
+	for root in _pyRootClasses:
+		try:
+			rootType=wrapper.__dict__[root]
+		except KeyError:
+			print 'WARNING: class %s not defined'%root
+		for p in childClasses(root):
+			proxyNamespace[p]=type(p,(rootType,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
+			_proxiedClasses.add(p)
+		# inject wrapped class itself into proxyNamespace
+		proxyNamespace[root]=rootType
+	# classes that derive just from Serializable: the remaining ones
+	for p in _allSerializables-_proxiedClasses-_pyRootClasses:
+		proxyNamespace[p]=type(p,(wrapper.Serializable,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
+	# deprecated names
+	for oldName in _deprecated.keys():
+		class warnWrap:
+			def __init__(self,_old,_new):
+				# assert(proxyNamespace.has_key(_new))
+				self.old,self.new=_old,_new
+			def __call__(self,*args,**kw):
+				import warnings; warnings.warn("Class `%s' was renamed to (or replaced by) `%s', update your code!"%(self.old,self.new),DeprecationWarning,stacklevel=2);
+				return proxyNamespace[self.new](*args,**kw)
+		proxyNamespace[oldName]=warnWrap(oldName,_deprecated[oldName])
+
+def setExitHandlers():
+	"""Set exit handler to avoid gdb run if log4cxx crashes at exit.
+	Remove excepthook."""
+	#import sys
+	# python2.4 workaround (so that quit() works as it does in 2.5)
+	if not callable(__builtins__['quit']):
+		def _quit(): import sys; sys.exit(0)
+		__builtins__['quit']=_quit
+	# avoid backtrace at regular exit, even if we crash
+	sys.exit=O.exitNoBacktrace
+	#sys.excepthook=sys.__excepthook__ # apport on ubuntu overrides this, we don't need it
+
+def runServers():
+	"""Run python telnet server and info socket. They will be run at localhost on ports 9000 (or higher if used) and 21000 (or higer if used) respectively.
+	
+	The python telnet server accepts only connection from localhost,
+	after authentication by random cookie, which is printed on stdout
+	at server startup.
+
+	The info socket provides read-only access to several simulation parameters
+	at runtime. Each connection receives pickled dictionary with those values.
+	This socket is primarily used by yade-multi batch scheduler.
+	"""
+	import yade.PythonTCPServer
+	srv=yade.PythonTCPServer.GenericTCPServer(handler=yade.PythonTCPServer.PythonConsoleSocketEmulator,title='TCP python prompt',cookie=True,minPort=9000)
+	yade.runtime.cookie=srv.server.cookie
+	info=yade.PythonTCPServer.GenericTCPServer(handler=yade.PythonTCPServer.InfoSocketProvider,title='TCP info provider',cookie=False,minPort=21000)
+	sys.stdout.flush()
+

=== modified file 'py/yadeWrapper/yadeWrapper.cpp'
--- py/yadeWrapper/yadeWrapper.cpp	2009-12-01 14:56:39 +0000
+++ py/yadeWrapper/yadeWrapper.cpp	2009-12-02 23:01:36 +0000
@@ -468,7 +468,7 @@
 	pyMaterialContainer materials_get(void){return pyMaterialContainer();}
 	
 
-	python::list listChildClasses(const string& base){
+	python::list listChildClassesNonrecursive(const string& base){
 		python::list ret;
 		for(map<string,DynlibDescriptor>::const_iterator di=Omega::instance().getDynlibsDescriptor().begin();di!=Omega::instance().getDynlibsDescriptor().end();++di) if (Omega::instance().isInheritingFrom((*di).first,base)) ret.append(di->first);
 		return ret;
@@ -713,7 +713,7 @@
 		.add_property("actions",&pyOmega::bex_get,"Deprecated alias for Omega().bex")
 		.add_property("bex",&pyOmega::bex_get,"BodyExternalVariables (forces, torques, ..) in  the current simulation.")
 		.add_property("tags",&pyOmega::tags_get,"Tags (string=string dictionary) of the current simulation (container supporting string-index access/assignment)")
-		.def("childClasses",&pyOmega::listChildClasses,"Return list of all classes deriving from given class, as registered in the class factory")
+		.def("childClassesNonrecursive",&pyOmega::listChildClassesNonrecursive,"Return list of all classes deriving from given class, as registered in the class factory")
 		.def("isChildClassOf",&pyOmega::isChildClassOf,"Tells whether the first class derives from the second one (both given as strings).")
 		.add_property("bodyContainer",&pyOmega::bodyContainer_get,&pyOmega::bodyContainer_set,"Get/set type of body container (as string); there must be no bodies.")
 		.add_property("interactionContainer",&pyOmega::interactionContainer_get,&pyOmega::interactionContainer_set,"Get/set type of interaction container (as string); there must be no interactions.")