HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PDG_EvaluationContext.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * COMMENTS:
7  */
8 
9 #ifndef __PDG_EVALUATION_CONTEXT_H__
10 #define __PDG_EVALUATION_CONTEXT_H__
11 
12 #include "PDG_API.h"
13 
14 #include "PDG_AttributeEvaluator.h"
15 #include "PDG_AttributeInfo.h"
16 
17 #include <PY/PY_Result.h>
18 
19 #include <UT/UT_ErrorManager.h>
20 #include <UT/UT_Function.h>
21 #include <UT/UT_NonCopyable.h>
22 #include <UT/UT_StringArray.h>
23 #include <UT/UT_StringMap.h>
24 
25 #include <SYS/SYS_Hash.h>
26 
27 #include <iosfwd>
28 
29 class PY_PyObject;
30 class PY_CompiledCode;
32 
34 class PDG_Graph;
35 class PDG_GraphContext;
36 class PDG_Node;
37 class PDG_WorkItem;
38 
39 class UT_IStream;
40 class UT_StringHolder;
41 class UT_WorkBuffer;
42 
43 /*
44  * A context for evaluation PDG Python expression. Each thread-local context has
45  * its own local dictionary which it uses to evaluate expressions, allowing
46  * node authors to insert their own local variables in node callbacks. The dict
47  * is cleared at the beginning of each callback invocation.
48  */
50 {
51 public:
52  /// Evaluation context state
53  enum State
54  {
59  eStateDirtying
60  };
61 
62  /// Enumeration of python script evaluation results
64  {
65  /// The script succeeded without any exceptions
67 
68  /// The script encountered an error or exception
70 
71  /// The script was aborted, e.g. with a sys.exit(..) call
72  eResultAbort
73  };
74 
75  /// Scoped reset of the thread-local context cooking/generation state
77  {
78  public:
79  StateScope(
80  int thread,
81  State state,
82  bool localize,
83  const PDG_Node* node,
84  const PDG_WorkItem* work_item,
85  PDG_GraphContext* context);
86  StateScope(
87  int thread,
88  State state,
89  bool localize,
90  const PDG_Node* node,
91  const PDG_WorkItem* work_item,
92  fpreal time);
93  ~StateScope();
95 
96  private:
97  void init(
98  int thread,
99  State state,
100  bool localize,
101  const PDG_Node* node,
102  const PDG_WorkItem* work_item,
103  fpreal time);
104 
105  private:
106  UT_AutoErrorManager myErrorManager;
107  const PDG_Node* myActiveNode;
108  const PDG_Node* myNode;
109  const PDG_WorkItem* myPreviousItem;
110  PY_PyObject* myLocals;
111  fpreal myEvalTime;
112  int myThread;
113 
114  State myState;
115  bool myParameterError;
116  bool myPushedDir;
117  bool myLocalize;
118  bool myPreviousParent;
119  };
120 
121  /// Scoped setter of local work item
123  {
124  public:
125  ItemScope(int thread,
126  const PDG_WorkItem* work_item,
127  bool is_parent);
128  ~ItemScope();
130 
131  private:
132  const PDG_WorkItem* myPreviousItem;
133  int myThread;
134  bool myPreviousParent;
135  };
136 
137  /// Scoped block that records PDG attribute evaluations
139  {
140  public:
142 
143  public:
147 
148  void reset();
149  void record(const UT_StringHolder& attrib);
150  const UT_StringArray& expressionAttribs() const
151  { return myExpressionAttribs; }
152 
153  private:
154  UT_StringArray myExpressionAttribs;
155  AttribRecordScope* myPreviousRecord;
156  int myThread;
157  };
158 
159  /// Utility function type for converting a PDG_WorkItem* to a PY_PyObject.
161 
162 public:
163  /// Constructs a new context. Should not be called, only here because the
164  /// thread local var needs it to be public instead of private.
167 
169 
170  /// Returns the built-in functions that are available in the the context
171  static void builtinFunctions(UT_StringArray& functions);
172 
173  /// Sets the work item caster function, which is used when setting a work
174  /// item as a Python dictonary variable from C++. If the caster function
175  /// is not installed, a slower code path that looks up the work item from
176  /// the graph is used instead.
177  static void setWorkItemCaster(
178  const WorkItemCaster& caster);
179 
180 
181  /// Configures whether or not all PDG_EvaluationContext instance should
182  /// use Python.
183  static void setUsePython(bool use_python);
184 
185  /// Returns the shared Python context in which expressions evaluated
186  static PY_EvaluationContext& getExpressionContext();
187 
188  /// Returns the thread-local PDG_EvaluationContext instance
189  static PDG_EvaluationContext* getContext();
190 
191  /// Returns the thread-local PDG_EvaluationContext instance for the
192  /// specific thread
193  static PDG_EvaluationContext* getContext(int thread);
194 
195 
196  /// Sets the global batch subitem index. Used when constructing an active
197  /// work item on the job side, to make attributes available.
198  static void setGlobalSubItemIndex(int index,
199  bool dirty);
200 
201  /// Sets the global active work item. Used for setting an active item
202  /// in the current houdini session for debugging, or as part of a houdini-
203  /// based job on the farm.
204  static void setGlobalWorkItem(
205  const PDG_WorkItem* work_item,
206  bool dirty);
207 
208  /// Sets the global active item for an out of process work item job
209  static void setGlobalJobWorkItem(
210  PDG_WorkItem* work_item,
211  const UT_StringHolder& node_name,
212  const UT_StringHolder& scheduler_name);
213 
214  /// Adds the specified attributes to the global set of time dependent
215  /// attribs, for out-of-process batch cooks that have different attribute
216  /// values at each frame.
217  static void setTimeDependentAttribs(
218  const UT_ArrayStringSet& names,
219  bool dirty);
220 
221  /// Dirties all dependent attributes
222  static void dirtyAllAttribs();
223 
224  /// Saves all attributes and field from the global active work item to the
225  /// specified output stream.
226  static bool saveGlobalWorkItem(std::ostream &os);
227 
228  /// Loads the data from the specified input stream into a free-standing
229  /// work item, which is saved as the default global item until one is
230  /// selected in the UI.
231  static bool loadGlobalWorkItem(UT_IStream& is);
232 
233  /// Quries the global work item. This should not be used in most cases,
234  /// except for when checking if the global item needs to be cleared
235  static const PDG_WorkItem* globalWorkItem(bool sub_item);
236 
237  /// Returns the global work item only if it's a work item loaded for an
238  /// out of process job, or nullptr in other cases
239  static const PDG_WorkItem* globalJobWorkItem(bool sub_item);
240 
241  /// Queries the global node name. Used on the job side to determine the
242  /// work item name, since the work item does not directly store a string
243  /// name on its own.
244  static const UT_StringHolder& globalNodeName();
245 
246  /// Queries the global scheduler name. Used on the job side to determine
247  /// the submitting scheduler name, since the work item doesn't have direct
248  /// access to the scheduler itself.
249  static const UT_StringHolder& globalSchedulerName();
250 
251  /// Returns true if PDG attribute evaluation is time dependent, else false
252  static bool useTimeDependentAttribs();
253 
254  /// Returns true if the specified attribute is time dependent, else false
255  static bool isTimeDependent(
256  const UT_StringHolder& name);
257 
258  /// Queries the current active work item. If a PDG cook is in-progress, this
259  /// will return the thread-local item. If there is no active cook, this will
260  /// return whatever global work item was set
261  static const PDG_WorkItem* activeWorkItem(int thread);
262 
263  /// Queries the thread local is-parent flag
264  static bool activeIsParent(int thread);
265 
266  /// Returns true if the thread local state is generating
267  static bool isLocalGenerating(int thread);
268 
269  /// Returns true if the thread local state is runtime
270  static bool isLocalRuntime(int thread);
271 
272  /// Returns true if the thread local state indicates the thread is being
273  /// used to do PDG work
274  static bool isLocalActive(int thread);
275 
276  /// Returns true if a PDG job is active, either in process or out of
277  /// process, for the specified thread. Out of process jobs that load in a
278  /// PDG work item are always considered to be active PDG jobs. Otherwise,
279  /// this method falls back to ::isLocalActive.
280  static bool isLocalCookingPDG(int thread);
281 
282  /// Returns the current state of the thread local evaluation context
283  static State localState(int thread);
284 
285  /// Returns the current evaluation time of the thread local context
286  static fpreal localEvalTime(int thread);
287 
288  /// Returns the thread-local active node
289  static const PDG_Node* localActiveNode(int thread);
290 
291 
292  /// Gets an attribute evaluator
293  static PDG_AttributeEvaluator* createAttributeEvaluator(int thread,
294  const char* name);
295 
296  /// Sets the Python evaluation dictionary directly
297  static void setDict(int thread, PY_PyObject* locals);
298 
299  /// Returns the local Python dictionary object
300  static PY_PyObject* localDict(int thread);
301 
302  /// Sets or updates primitive values in the Python dictionary
303  static void updateDict(int thread,
304  const UT_StringHolder& name,
305  fpreal value);
306  static void updateDict(int thread,
307  const UT_StringHolder& name,
308  int value);
309  static void updateDict(int thread,
310  const UT_StringHolder& name,
311  const UT_StringHolder& value);
312 
313  /// Sets or updates a PDG work in the Python dictionary
314  static void updateDict(int thread,
315  const UT_StringHolder& name,
316  const PDG_WorkItem* work_item);
317 
318  /// Sets or updates a PDG node in the Python dictionary
319  static void updateDict(int thread,
320  const UT_StringHolder& name,
321  const PDG_Node* node);
322 
323  /// Sets or update a PDG graph inthe Python dictionary
324  static void updateDict(int thread,
325  const UT_StringHolder& name,
326  const PDG_Graph* graph);
327 
328  /// Resets the thread-local context's local Python dictionary
329  static void resetDict(int thread);
330 
331 
332  /// Primitive Python eval methods (loat, int, string)
333  static EvaluationResult evaluate(int thread,
334  const PY_CompiledCode& expression,
335  fpreal& result,
336  UT_WorkBuffer& errors);
337  static EvaluationResult evaluate(int thread,
338  const PY_CompiledCode& expression,
339  exint& result,
340  UT_WorkBuffer& errors);
341  static EvaluationResult evaluate(int thread,
342  const PY_CompiledCode& expression,
343  UT_StringHolder& result,
344  UT_WorkBuffer& errors);
345 
346  /// PyObject eval method
347  static EvaluationResult evaluate(int thread,
348  const PY_CompiledCode& expression,
349  void*& result,
350  UT_WorkBuffer& errors);
351 
352  /// Void/no-result eval method
353  static EvaluationResult evaluate(int thread,
354  const PY_CompiledCode& expression,
355  UT_WorkBuffer& errors);
356 
357  /// Evaluates an abritrary string and returns the PyObject, rather than
358  /// evaluating a compiled code instance.
359  static EvaluationResult evaluateCodeString(
360  int thread,
361  const UT_StringHolder& raw_code,
362  void*& result,
363  bool multi,
364  UT_WorkBuffer& errors);
365 
366  /// Saves a PyObject attribute to a string
367  static bool savePyObjectAttr(
368  int thread,
369  UT_StringHolder& result,
370  const PDG_AttributePyObject* attr,
371  const UT_StringHolder& module);
372 
373  /// Loads a PyObject attribute to a string
374  static bool loadPyObjectAttr(
375  int thread,
376  void*& result,
377  const UT_StringHolder& attr_data,
378  const UT_StringHolder& module);
379 
380  /// Cooks work item with the specified job script module
381  static bool cookWorkItem(
382  int thread,
383  const UT_StringHolder& module,
384  PDG_WorkItem* work_item,
385  UT_WorkBuffer& errors);
386 
387  /// Hashes a PyOvject attribute
388  static bool hashPyObjectAttr(
389  SYS_HashType& result,
390  const PDG_AttributePyObject* attr,
391  UT_WorkBuffer& errors);
392 
393  /// Updates parameter error state
394  static void updateParameterEvaluation(
395  int thread,
396  bool has_error);
397 
398 public:
399  /// Returns the context's active work item
400  const PDG_WorkItem* workItem() const;
401 
402  /// Returns true if the local work item is the parent item for the
403  /// evaluation
404  bool isParent() const;
405 
406  /// Returns the active node for the the context
407  const PDG_Node* activeNode() const;
408 
409  /// Returns the state of the context
410  State state() const;
411 
412  /// Returns the parameter evaluation state of the context
413  bool hasParameterError() const;
414 
415  /// Returns the current evaluation time of the context
416  fpreal evalTime() const;
417 
418  /// Returns true if the context is in a generating state
419  bool isGenerating() const
420  { return (myState == eStateStatic) ||
421  (myState == eStateDynamic); }
422 
423  /// Returns true if the context is in a cooking state
424  bool isCooking() const
425  { return (myState == eStateCooking); }
426 
427  /// Returns true if the context is in a runtime state
428  bool isRuntime() const
429  { return (myState == eStateDynamic) ||
430  (myState == eStateCooking) ||
431  (myState == eStateNone); }
432 
433 
434  /// Returns true if the context is actively doing PDG work
435  bool isActive() const
436  { return myState != eStateNone; }
437 
438  /// Returns true if the context should force file paths to be localized
439  bool isLocalize() const
440  { return myIsLocalize; }
441 
442  /// Returns true if the specified work item can be dirtied in the
443  /// current context
444  bool canDirty(const PDG_WorkItem* work_item) const;
445 
446  /// Returns true if the specified node can be dirtied in the current
447  /// context
448  bool canDirty(const PDG_Node* node) const;
449 
450  /// General version of the above method that can be called without a node
451  bool canDirty() const;
452 
453  /// Records an attribute access with the active scope block, if one has
454  /// been set
456  {
457  if (myAttributeRecord)
458  myAttributeRecord->record(name);
459  }
460 
461 private:
462  /// Internal initialize logic
463  void init();
464 
465  /// Internal reset logic
466  void reset();
467 
468  /// Returns the local dictionary
469  PY_PyObject* dict() const;
470 
471  /// Returns the context's local work item
472  const PDG_WorkItem* activeWorkItem() const;
473 
474  /// Returns the context's current attribute record block, or nullptr if
475  /// one has not been set.
476  AttribRecordScope* attributeRecord() const;
477 
478  /// Gets/Sets the local work item
479  void setWorkItem(const PDG_WorkItem* work_item,
480  bool parent);
481 
482  /// Sets the active node for the context
483  void setActiveNode(const PDG_Node* node);
484 
485  /// Sets the context state
486  void setState(State state);
487 
488  /// Sets the context parameter evaluation state
489  void setParameterError(bool has_error);
490 
491  /// Sets the context eval time
492  void setEvalTime(fpreal time);
493 
494  /// Sets the forced localization flag
495  void setLocalize(bool localize);
496 
497  /// Set the active attribute record scope
498  void setAttributeRecord(AttribRecordScope* scope);
499 
500  /// Adds an attribute evaluator to the map, or returns one if it already
501  /// exists. Templated so the caller can select the type
502  PDG_AttributeEvaluator* attributeEvaluator(const char* name);
503 
504  /// Generic evaluation method that returns the result of an expression in
505  /// a PY_Result object
506  EvaluationResult evaluate(const PY_CompiledCode& expression,
508  PY_Result& result,
509  bool include_details,
510  UT_WorkBuffer& errors);
511 
512  /// Sets the local dictionary. If the locals object is nullptr, resets the
513  /// dictionary to an empty dict
514  void setLocalDict(PY_PyObject* locals);
515 
516  /// Copies the local dict if it has modifications, else returns a nullptr
517  PY_PyObject* saveLocalDict();
518 
519  /// Restores and frees the local dict
520  void restoreLocalDict(PY_PyObject* locals);
521 
522  /// Sets a local dictionary entry by running a script
523  void setLocalDictEntryByScript(
524  const UT_StringHolder& name,
525  const char* py_expression);
526  /// Sets a local dictionary entry as a PyObject
527  void setLocalDictEntryByObject(
528  const UT_StringHolder& name,
529  PY_PyObject* py_obj);
530 
531 private:
533 
534  PY_PyObject* myLocalDict;
535  const PDG_WorkItem* myActiveWorkItem;
536  const PDG_Node* myActiveNode;
537  EvaluatorMap myAttributeMap;
538  AttribRecordScope* myAttributeRecord;
539  fpreal myEvalTime;
540 
541  State myState;
542 
543  bool myDictModified : 1;
544  bool myIsParent : 1;
545  bool myIsLocalize : 1;
546  bool myHasParameterError : 1;
547 };
548 
549 #endif
OIIO_API bool has_error()
Is there a pending global error message waiting to be retrieved?
void
Definition: png.h:1083
GT_API const UT_StringHolder time
#define PDG_API
Definition: PDG_API.h:23
State
Evaluation context state.
int64 exint
Definition: SYS_Types.h:125
std::size_t SYS_HashType
Define the type for hash values.
Definition: SYS_Hash.h:19
UT_Function< PY_PyObject *(const PDG_WorkItem *)> WorkItemCaster
Utility function type for converting a PDG_WorkItem* to a PY_PyObject.
**But if you need a result
Definition: thread.h:613
EvaluationResult
Enumeration of python script evaluation results.
bool isActive() const
Returns true if the context is actively doing PDG work.
Scoped setter of local work item.
GLboolean reset
Definition: glad.h:5138
The script succeeded without any exceptions.
PY_PyObject
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
The script encountered an error or exception.
bool isCooking() const
Returns true if the context is in a cooking state.
GLuint const GLchar * name
Definition: glcorearb.h:786
Scoped block that records PDG attribute evaluations.
std::function< T > UT_Function
Definition: UT_Function.h:37
**Note that the tasks the is the thread number *for the or if it s being executed by a non pool thread(this *can happen in cases where the whole pool is occupied and the calling *thread contributes to running the work load).**Thread pool.Have fun
fpreal64 fpreal
Definition: SYS_Types.h:277
GLuint index
Definition: glcorearb.h:786
bool isRuntime() const
Returns true if the context is in a runtime state.
Definition: core.h:1131
bool isLocalize() const
Returns true if the context should force file paths to be localized.
UT_ErrorManager::Scope UT_AutoErrorManager
Alias UT_AutoErrorManager as UT_ErrorManager::Scope.
Scoped reset of the thread-local context cooking/generation state.
type
Definition: core.h:1059
void recordAttribute(const UT_StringHolder &name)