<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugzilla.yoctoproject.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.6"
          urlbase="https://bugzilla.yoctoproject.org/"
          
          maintainer="it-coreprojects-helpdesk@linuxfoundation.org"
>

    <bug>
          <bug_id>7668</bug_id>
          
          <creation_ts>2015-04-27 23:07:23 +0000</creation_ts>
          <short_desc>Feature request: inject &apos;d&apos; as well as &apos;e&apos; into event handlers</short_desc>
          <delta_ts>2015-09-10 07:21:08 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>7</classification_id>
          <classification>Build System, Metadata &amp; Runtime</classification>
          <product>BitBake</product>
          <component>bitbake</component>
          <version>unspecified</version>
          <rep_platform>x86</rep_platform>
          <op_sys>Multiple</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>Medium</priority>
          <bug_severity>enhancement</bug_severity>
          <target_milestone>1.9 M1</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Christopher Larson">kergoth</reporter>
          <assigned_to name="Richard Purdie">richard.purdie</assigned_to>
          <cc>bluelightning</cc>
    
    <cc>bogdanx.a.voiculescu</cc>
    
    <cc>poky.bs.watcher</cc>
    
    <cc>poky.watcher</cc>
          
          <qa_contact name="Lucian Musat">georgex.l.musat</qa_contact>
          <cf_os>---</cf_os>
          <cf_regression_type>---</cf_regression_type>
          
          <cf_docchange>Yes (doc changes required)</cf_docchange>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>50541</commentid>
    <comment_count>0</comment_count>
    <who name="Christopher Larson">kergoth</who>
    <bug_when>2015-04-27 23:07:23 +0000</bug_when>
    <thetext>e.data.getVar() gets a bit old in a large event handler, and it means a simple handler has to be modified if switching between an event handler (e.g. RecipeParsed) and anonymous python. I think it would make sense to restore the &apos;d&apos; convention here to align with python elsewhere. It&apos;d just be a convenience, d==e.data, to avoid the common pattern of setting it at the top of the event handler.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>51818</commentid>
    <comment_count>1</comment_count>
    <who name="Richard Purdie">richard.purdie</who>
    <bug_when>2015-06-19 07:48:59 +0000</bug_when>
    <thetext>I had a look at doing this, it turns out to be quite hard/ugly.

The issue is that the event handler code is precompiled and takes a single argument, e. In order to get the same behaviour as anonymous python, we&apos;d need to pass d into the locals() of the function but to do that, as far as I can tell we need exec/eval. exec/eval don&apos;t work with functions which take parameters.

There are tricks you can use to exec/eval functions with parameters but they work by wrapping the function, then we lose the ability to influence locals again.

I also tried injecting d into globals() however globals() is module specific and we therefore can&apos;t access globals past the first function exec where a different namespace takes over.

This left __builtins__ and something like:

diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
index f755eb2..80e3796 100644
--- a/bitbake/lib/bb/event.py
+++ b/bitbake/lib/bb/event.py
@@ -72,6 +72,7 @@ _eventfilter = None
 
 def execute_handler(name, handler, event, d):
     event.data = d
+    __builtins__[&apos;d&apos;] = d
     try:
         ret = handler(event)
     except bb.parse.SkipRecipe:
@@ -87,6 +88,7 @@ def execute_handler(name, handler, event, d):
             logger.error(&quot;Execution of event handler &apos;%s&apos; failed (exit code %s)&quot; % (name, exc.code))
     finally:
         del event.data
+        del __builtins__[&apos;d&apos;]
 
 def fire_class_handlers(event, d):
     if isinstance(event, logging.LogRecord):


does work. Do we accept that ugliness though?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>51857</commentid>
    <comment_count>2</comment_count>
    <who name="Christopher Larson">kergoth</who>
    <bug_when>2015-06-22 17:44:03 +0000</bug_when>
    <thetext>Is there a reason we don&apos;t just add a second argument? I realize it&apos;s probably not conceptually ideal, since setting d is just a convenience, but it would work. As far as I know, the only code which compiles the handler functions is bb.event.register(), so it should be trivial to change the signature of the handler functions.

Alternatively, we could inject d = e.data as the first line of the functions, but then we&apos;d need a way to adjust the line numbers for tracebacks, so probably not worthwhile.

diff --git i/bitbake/lib/bb/event.py w/bitbake/lib/bb/event.py
index ba0de11..1399ba5 100644
--- i/bitbake/lib/bb/event.py
+++ w/bitbake/lib/bb/event.py
@@ -73,7 +73,7 @@ _eventfilter = None
 def execute_handler(name, handler, event, d):
     event.data = d
     try:
-        ret = handler(event)
+        ret = handler(event, d)
     except (bb.parse.SkipRecipe, bb.BBHandledException):
         raise
     except Exception:
@@ -180,9 +180,9 @@ def register(name, handler, mask=[]):
     if handler is not None:
         # handle string containing python code
         if isinstance(handler, basestring):
-            tmp = &quot;def %s(e):\n%s&quot; % (name, handler)
+            tmp = &quot;def %s(e, d):\n%s&quot; % (name, handler)
             try:
-                code = compile(tmp, &quot;%s(e)&quot; % name, &quot;exec&quot;)
+                code = compile(tmp, &quot;%s(e, d)&quot; % name, &quot;exec&quot;)
             except SyntaxError:
                 logger.error(&quot;Unable to register event handler &apos;%s&apos;:\n%s&quot;, name,
                              &apos;&apos;.join(traceback.format_exc(limit=0)))</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>51935</commentid>
    <comment_count>3</comment_count>
    <who name="Richard Purdie">richard.purdie</who>
    <bug_when>2015-06-25 15:21:49 +0000</bug_when>
    <thetext>http://git.yoctoproject.org/cgit.cgi/poky/commit/?id=df123ddab43a221cc26028e0aff211ac34c1eafc(In reply to comment #2)
&gt; Is there a reason we don&apos;t just add a second argument? I realize it&apos;s
&gt; probably not conceptually ideal, since setting d is just a convenience, but
&gt; it would work. As far as I know, the only code which compiles the handler
&gt; functions is bb.event.register(), so it should be trivial to change the
&gt; signature of the handler functions.
&gt; 
&gt; Alternatively, we could inject d = e.data as the first line of the
&gt; functions, but then we&apos;d need a way to adjust the line numbers for
&gt; tracebacks, so probably not worthwhile.
&gt; 
&gt; diff --git i/bitbake/lib/bb/event.py w/bitbake/lib/bb/event.py
&gt; index ba0de11..1399ba5 100644
&gt; --- i/bitbake/lib/bb/event.py
&gt; +++ w/bitbake/lib/bb/event.py
&gt; @@ -73,7 +73,7 @@ _eventfilter = None
&gt;  def execute_handler(name, handler, event, d):
&gt;      event.data = d
&gt;      try:
&gt; -        ret = handler(event)
&gt; +        ret = handler(event, d)
&gt;      except (bb.parse.SkipRecipe, bb.BBHandledException):
&gt;          raise
&gt;      except Exception:
&gt; @@ -180,9 +180,9 @@ def register(name, handler, mask=[]):
&gt;      if handler is not None:
&gt;          # handle string containing python code
&gt;          if isinstance(handler, basestring):
&gt; -            tmp = &quot;def %s(e):\n%s&quot; % (name, handler)
&gt; +            tmp = &quot;def %s(e, d):\n%s&quot; % (name, handler)
&gt;              try:
&gt; -                code = compile(tmp, &quot;%s(e)&quot; % name, &quot;exec&quot;)
&gt; +                code = compile(tmp, &quot;%s(e, d)&quot; % name, &quot;exec&quot;)
&gt;              except SyntaxError:
&gt;                  logger.error(&quot;Unable to register event handler &apos;%s&apos;:\n%s&quot;,
&gt; name,
&gt;                               &apos;&apos;.join(traceback.format_exc(limit=0)))

The reason I didn&apos;t do this is that that under that if block, the register function would appear to take functions as handlers as well as strings. Those functions would then break. At the time I assumed something used that code path, perhaps it doesn&apos;t though?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>51953</commentid>
    <comment_count>4</comment_count>
    <who name="Richard Purdie">richard.purdie</who>
    <bug_when>2015-06-26 08:31:59 +0000</bug_when>
    <thetext>http://git.yoctoproject.org/cgit.cgi/poky/commit/?id=df123ddab43a221cc26028e0aff211ac34c1eafc
http://git.yoctoproject.org/cgit.cgi/poky/commit/?id=8c3dd2d9eb2c593d5b7cf28d7627e6725ab7dbfe
Still considering the change Chris proposed though...</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>