H3D API  2.4.1
PythonMethods.h
Go to the documentation of this file.
1 // Copyright 2004-2019, SenseGraphics AB
3 //
4 // This file is part of H3D API.
5 //
6 // H3D API is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // H3D API is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with H3D API; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // A commercial license is also available. Please contact us at
21 // www.sensegraphics.com for more information.
22 //
23 //
28 //
30 #ifndef __PYTHONMETHODS_H__
31 #define __PYTHONMETHODS_H__
32 #include <H3D/Field.h>
33 #include <H3D/X3DTypes.h>
34 #include <H3D/X3DFieldConversion.h>
35 #include <H3D/X3DTypeFunctions.h>
36 #include <H3D/PythonScript.h>
37 #include <H3D/Profiling.h>
38 
39 #ifdef HAVE_PYTHON
40 #if defined(_MSC_VER)
41 // undefine _DEBUG since we want to always link to the release version of
42 // python and pyconfig.h automatically links debug version if _DEBUG is
43 // defined.
44 #if defined _DEBUG && ! defined HAVE_PYTHON_DEBUG_LIBRARY
45 #define _DEBUG_UNDEFED
46 #undef _DEBUG
47 #endif
48 
49 #include <pyconfig.h>
50 
51 // define HAVE_ROUND if not defined
52 #if _MSC_VER >= 1800
53 #ifndef HAVE_ROUND
54 #define HAVE_ROUND 1
55 #endif
56 #endif // _MSC_VER >= 1800
57 
58 #endif
59 #if defined(__APPLE__) && defined(__MACH__) && defined( HAVE_PYTHON_OSX_FRAMEWORK )
60 #include <Python/Python.h>
61 #else
62 #ifdef __GNUC__
63 #ifdef _POSIX_C_SOURCE
64 #undef _POSIX_C_SOURCE
65 #endif
66 #ifdef _XOPEN_SOURCE
67 #undef _XOPEN_SOURCE
68 #endif
69 #endif
70 #include <Python.h>
71 #endif
72 #if defined(_MSC_VER)
73 // redefine _DEBUG if it was undefed
74 #ifdef _DEBUG_UNDEFED
75 #define _DEBUG
76 #endif
77 #endif
78 
80 
81 #include <sstream>
82 
83 namespace H3D {
84  struct PyNode; // Forward declare
85  namespace PythonInternals {
86 #if PY_MAJOR_VERSION >= 3
87  PyMODINIT_FUNC PyInit_H3D( void );
88 #else
89  PyMODINIT_FUNC initH3D();
90 #endif
91 
92  H3DAPI_API PyObject * initH3DInternal();
93  H3DAPI_API void finishH3DInternal();
94 
95  double pyObjectToDouble( PyObject *v );
96 
97  void fieldDestructor( void *f );
98 
99  PyObject *fieldAsPythonObject( Field * f, bool destruct = false, PyNode * owner_pynode = NULL );
100 
101  PyObject *pythonCreateField( PyObject *self, PyObject *args );
102 
103  bool pythonSetFieldValueFromObject( Field *field_ptr, PyObject *v );
104 
105  PyObject *pythonFieldSetValue( PyObject *self, PyObject *args );
106 
107  PyObject *pythonFieldGetValue( PyObject *self, PyObject *arg );
108 
109  PyObject *pythonFieldSetAccessType( PyObject *self, PyObject *arg );
110 
111  PyObject *pythonFieldGetAccessType( PyObject *self, PyObject *arg );
112 
113  PyObject *pythonFieldSetAccessCheck( PyObject *self, PyObject *arg );
114 
115  PyObject *pythonFieldIsAccessCheckOn( PyObject *self, PyObject *arg );
116 
117  PyObject *pythonFieldRoute( PyObject *self, PyObject *args );
118 
119  PyObject *pythonFieldRouteNoEvent( PyObject *self, PyObject *args );
120 
121  PyObject *pythonFieldUnroute( PyObject *self, PyObject *args );
122 
123  PyObject *pythonFieldReplaceRoute( PyObject *self, PyObject *args );
124 
125  PyObject *pythonFieldReplaceRouteNoEvent( PyObject *self, PyObject *args );
126 
127  PyObject *pythonFieldUnrouteAll( PyObject *self, PyObject *arg );
128 
129  PyObject *pythonSFStringIsValidValue( PyObject *self, PyObject *args );
130 
131  PyObject *pythonSFStringGetValidValues( PyObject *self, PyObject *args );
132 
133  PyObject *pythonGetCPtr( PyObject *self, PyObject *arg );
134 
135  PyObject* pythonCreateX3DFromURL( PyObject *self, PyObject *arg );
136 
137  PyObject* pythonCreateX3DFromString( PyObject *self, PyObject *arg );
138 
139  PyObject* pythonCreateX3DNodeFromURL( PyObject *self, PyObject *arg );
140 
141  PyObject* pythonCreateX3DNodeFromString( PyObject *self, PyObject *arg );
142 
143  PyObject* pythonCreateVRMLFromURL( PyObject *self, PyObject *arg );
144 
145  PyObject* pythonCreateVRMLFromString( PyObject *self, PyObject *arg );
146 
147  PyObject* pythonWriteNodeAsX3D( PyObject *self, PyObject *arg );
148 
149  PyObject* pythonCreateVRMLNodeFromURL( PyObject *self, PyObject *arg );
150 
151  PyObject* pythonCreateVRMLNodeFromString( PyObject *self, PyObject *arg );
152 
153  PyObject* pythonFieldRoutesTo( PyObject *self, PyObject *arg );
154 
155  PyObject* pythonFieldHasRouteFrom( PyObject *self, PyObject *arg );
156 
157  PyObject* pythonFieldGetRoutesIn( PyObject *self, PyObject *arg );
158 
159  PyObject* pythonFieldGetRoutesOut( PyObject *self, PyObject *arg );
160 
161  PyObject* pythonGetCurrentScenes( PyObject *self, PyObject *arg );
162 
163  PyObject* pythonGetActiveDeviceInfo( PyObject *self, PyObject *arg );
164 
165  PyObject* pythonGetActiveBindableNode( PyObject *self, PyObject *arg );
166 
167  PyObject* pythonGetActiveViewpoint( PyObject *self, PyObject *arg );
168 
169  PyObject* pythonGetActiveNavigationInfo( PyObject *self, PyObject *arg );
170 
171  PyObject* pythonGetActiveStereoInfo( PyObject *self, PyObject *arg );
172 
173  PyObject* pythonGetActiveBackground( PyObject *self, PyObject *arg );
174 
175  PyObject* pythonGetActiveFog( PyObject *self, PyObject *arg );
176 
177  PyObject* pythonGetActiveGlobalSettings( PyObject *self, PyObject *arg );
178 
179  PyObject* pythonMFieldErase( PyObject *self, PyObject *arg );
180 
181  PyObject* pythonMFieldPushBack( PyObject *self, PyObject *arg );
182 
183  PyObject* pythonMFieldClear( PyObject *self, PyObject *arg );
184 
185  PyObject* pythonMFieldBack( PyObject *self, PyObject *arg );
186 
187  PyObject* pythonMFieldFront( PyObject *self, PyObject *arg );
188 
189  PyObject* pythonMFieldEmpty( PyObject *self, PyObject *arg );
190 
191  PyObject* pythonMFieldPopBack( PyObject *self, PyObject *arg );
192 
193  PyObject* pythonMFieldSize( PyObject *self, PyObject *arg );
194 
195  PyObject* pythonFieldTouch( PyObject *self, PyObject *arg );
196 
197  PyObject* pythonResolveURLAsFile( PyObject *self, PyObject *arg );
198 
199  PyObject* pythonResolveURLAsFolder( PyObject *self, PyObject *arg );
200 
201  PyObject* throwQuitAPIException( PyObject *self, PyObject *arg );
202 
203  PyObject* pythonCreateNode( PyObject* self, PyObject* arg, PyObject* keywds );
204 
205  PyObject* pythonGetHapticsDevice( PyObject *self, PyObject *arg );
206 
207  PyObject* pythonGetNrHapticsDevices( PyObject *self, PyObject *arg );
208 
209  PyObject* pythonGetNamedNode( PyObject *self, PyObject *arg );
210 
211  PyObject* pythonFieldSetName( PyObject *self, PyObject *arg );
212 
213  PyObject* pythonFieldGetName( PyObject *self, PyObject *arg );
214 
215  PyObject* pythonFieldGetFullName( PyObject *self, PyObject *arg );
216 
217  PyObject* pythonFieldGetTypeName( PyObject *self, PyObject *arg );
218 
219  PyObject* pythonFieldGetOwner( PyObject *self, PyObject *arg );
220 
221  PyObject* pythonFieldSetOwner( PyObject *self, PyObject *arg );
222 
223  PyObject* pythonFieldGetValueAsString( PyObject *self, PyObject *arg );
224 
225  PyObject* pythonFieldSetValueFromString( PyObject *self, PyObject *arg );
226 
227  PyObject* pythonFieldUpToDate( PyObject *self, PyObject *arg );
228 
229  PyObject* pythonFieldIsUpToDate( PyObject *self, PyObject *arg );
230 
232  PyObject* pythonAddProgramSetting( PyObject *self, PyObject *arg );
233 /*
234  PyObject* pythonRemoveProgramSetting( PyObject *self, PyObject *arg );
235 
236  PyObject* pythonClearProgramSettings( PyObject *self, PyObject *arg );
237 
238  PyObject* pythonGetProgramSetting( PyObject *self, PyObject *arg );
239 
240  PyObject* pythonGetProgramSettings( PyObject *self, PyObject *arg );
241 */
242 
243  PyObject* pythonFindNodes( PyObject *self, PyObject *arg );
244 
245  PyObject* pythonTakeScreenshot( PyObject *self, PyObject *arg );
246 
247  PyObject* pythonAddURNResolveRule( PyObject *self, PyObject *arg );
248 
249  PyObject* pythonExportGeometryAsSTL( PyObject *self, PyObject *args );
250  }
251 
252 
258 
259  struct PythonFieldBase {
260  PythonFieldBase( void *_python_field ) :
261  python_field( _python_field ),
262  have_update( false ),
263  have_type_info( false ),
264  have_opt_type_info( false ) {
266  python_fields.insert( this );
267  }
268 
269  virtual ~PythonFieldBase() {
271  python_fields.erase( this );
272  }
273  static H3DAPI_API std::set< PythonFieldBase * > python_fields;
274  void *python_field;
275  // Flags used to know if the "update", "__type_info_", "__opt_type_info__"
276  // attributes of the python fields exists and should be used.
277  // Note that the these attributes can not be added to the field after
278  // pythonCreateField is called.
279  // The reason for not simply storing a pointer to a c-version of those
280  // attributes is because PyObject_GetAttrString increases the reference
281  // count to the field and therefore we would have circular dependency
282  // for destructing. Which means that reloading of new PythonScripts would
283  // not work properly in browsers, for example H3DViewer.
284  bool have_update;
285  bool have_type_info;
286  bool have_opt_type_info;
287  };
288 
289  template< class F >
290  struct PythonField : public F, PythonFieldBase {
291 
292  PythonField( void *_python_field ) :
293  PythonFieldBase( _python_field ) {
294  }
295 
296  virtual void update() {
297 #ifdef HAVE_PROFILER
298  if( Profiling::profile_python_fields ) {
299  H3DUtil::H3DTimer::stepBegin( getName().c_str(), "PYTHON" );
300  }
301 #endif
302 
303  // ensure we have the GIL lock to work with multiple python threads.
304  PyGILState_STATE state = PyGILState_Ensure();
305  if( have_update ) {
306  PyObject *python_update = PyObject_GetAttrString(
307  static_cast<PyObject *>(python_field), "update" );
308  PyErr_Clear();
309  if( python_update ) {
310  PyObject *args = PyTuple_New( 1 );
311  PyObject *f = PythonInternals::fieldAsPythonObject( this->event.ptr, false );
312  PyTuple_SetItem( args, 0, f );
313  // For python 3.9 we could use function PyObject_CallOneArg instead of PyObject_CallObject
314  // but since we allow for other python versions use a more general version.
315  PyObject *r = PyObject_CallObject( python_update,
316  args );
317  Py_DECREF( args );
318  // Note: Fields that contain nodes must be able to return None to represent NULL
319  // For other fields it is probably a missing return statement, so warn in this case
320  if( r == Py_None && this->getX3DType() != X3DTypes::SFNODE && this->getX3DType() != X3DTypes::MFNODE ) {
321  Console( LogLevel::Warning ) << "Warning: update()-function for Python defined field of type "
322  << this->getFullName() << " does not return a value. " << endl;
323  Py_DECREF( r );
324  } else if( r ) {
325  if( !PythonInternals::pythonSetFieldValueFromObject( this, r ) ) {
326  std::stringstream ss;
327  ss << "Warning: invalid return value from update()-function"
328  << " for Python defined field of type "
329  << this->getFullName();
330  bool is_MField = (this->getX3DType() % 2 != 0);
331  if( is_MField && !PyList_Check( r ) ) {
332  ss << ". The field is a MField which requires a list of values to be returned"
333  << " while the current return value is not a list.";
334  }
335  Console( LogLevel::Warning ) << ss.str() << std::endl;
336  PyObject* err = PyErr_Occurred();
337  if( err != NULL ) {
338  PyErr_Print();
339  }
340  }
341  Py_DECREF( r );
342  } else {
343  PyObject* err = PyErr_Occurred();
344  if( err != NULL ) {
345  PyErr_Print();
346  }
347  }
348  Py_DECREF( python_update );
349  } else {
350  F::update();
351  }
352  } else {
353  F::update();
354  }
355  PyGILState_Release( state );
356 #ifdef HAVE_PROFILER
357  if( Profiling::profile_python_fields ) {
358  H3DUtil::H3DTimer::stepEnd( getName() );
359  }
360 #endif
361  }
362 
370  void checkFieldType( Field *f, int index ) {
371  if( have_type_info == 0 && have_opt_type_info == 0 ) {
372  F::checkFieldType( f, index );
373  return;
374  }
375 
376  // ensure we have the GIL lock to work with multiple python threads.
377  PyGILState_STATE state = PyGILState_Ensure();
378 
379  PyObject *python_typeinfo = PyObject_GetAttrString(
380  static_cast<PyObject *>(python_field), "__type_info__" );
381  PyErr_Clear();
382 
383  int arg_size = -1;
384  if( python_typeinfo )
385  arg_size = (int)PyTuple_Size( static_cast<PyObject *>(python_typeinfo) );
386 
387  if( index >= arg_size ) {
388  PyObject *python_opttypeinfo = PyObject_GetAttrString(
389  static_cast<PyObject *>(python_field), "__opt_type_info__" );
390  PyErr_Clear();
391  int opt_arg_size = -1;
392  if( python_opttypeinfo )
393  opt_arg_size = (int)PyTuple_Size( static_cast<PyObject *>(python_opttypeinfo) );
394  if( opt_arg_size > 0 ) {
395  PyObject *type_info =
396  PyTuple_GetItem( static_cast<PyObject *>(python_opttypeinfo),
397  0 );
398  PyObject *type_id = PyObject_GetAttrString( type_info, "type" );
399  int type_int = PyInt_AsLong( type_id );
400  if( f->getTypeName().compare(
401  X3DTypes::typeToString( (X3DTypes::X3DType)type_int ) ) != 0 ) {
402  ostringstream err;
403  err << "Bad input, expected "
404  << X3DTypes::typeToString( (X3DTypes::X3DType)type_int )
405  << " got " << f->getTypeName() << " for route" << index;
406  PyGILState_Release( state );
407  throw H3D::PythonInvalidFieldType( err.str(), "",
408  H3D_FULL_LOCATION );
409  }
410  } else {
411  ostringstream err;
412  err << "Too many inputs, expected " << arg_size + 1;
413  PyGILState_Release( state );
414  throw H3D::PythonInvalidFieldType( err.str(), "",
415  H3D_FULL_LOCATION );
416  }
417  } else if( python_typeinfo ) {
418  PyObject *type_info =
419  PyTuple_GetItem( static_cast<PyObject *>(python_typeinfo),
420  index );
421  PyObject *type_id = PyObject_GetAttrString( type_info, "type" );
422  int type_int = PyInt_AsLong( type_id );
423  //if( ! t || ! PyInt_Check( t ) )
424 
425  // check that field type is of correct type. The comparison
426  // with UNKNOWN_X3D_TYPE is to allow Python fields to accept
427  // Field as input, thus allowing any field type to be routed
428  // to it.
429  if( f->getTypeName().compare(
430  X3DTypes::typeToString( (X3DTypes::X3DType)type_int ) ) != 0 &&
431  strcmp( X3DTypes::typeToString( (X3DTypes::X3DType)type_int ),
432  "UNKNOWN_X3D_TYPE" ) != 0 ) {
433  ostringstream err;
434  err << "Bad input, expected "
435  << X3DTypes::typeToString( (X3DTypes::X3DType)type_int )
436  << " got " << f->getTypeName() << " for route" << index;
437  throw H3D::PythonInvalidFieldType( err.str(), "",
438  H3D_FULL_LOCATION );
439  }
440  }
441  PyGILState_Release( state );
442  }
443  };
444 }
445 
446 #endif // HAVE_PYTHON
447 #endif
Contains the Field class.
Header file for .
Defines and function for easy porting to Python 3.
PyObject * pythonAddProgramSetting(PyObject *self, PyObject *arg)
addProgramSettings( field, setting_name = "", section = "" )
Definition: PythonMethods.cpp:3110
Script node for python scripting.
This file contains functions for convertion from a string to a value of an X3D field type.
Header file containing useful functions for conversions of different representations of X3D types.
Header file containing all X3D types enumerated.
static bool inMainThread()
An exception thrown when a field is of the wrong type when it is checked.
Definition: PythonMethods.h:257
H3D_VALUE_EXCEPTION(string, InvalidType)
An exception thrown when a field is of the wrong type when it is checked.
H3D API namespace.
Definition: Anchor.h:38