I'm guessing the button is generated via form.add_button(), which uses 
TAG['button'], which generates a __tag_div__ object, which is pickled with 
the custom TAG_pickler function:

def TAG_pickler(data):
    d = DIV()
    d.__dict__ = data.__dict__
    marshal_dump = pickle.dumps(d, pickle.HIGHEST_PROTOCOL)
    return (TAG_unpickler, (marshal_dump,))

When a web2py HTML DOM element is nested inside another element, its 
__dict__ has a reference to the parent element, resulting in a recursive 
object. This is generally not a problem for pickle, but I guess the the 
fact that TAG_pickler creates a new DIV object and copies the __dict__ of 
the original __tag_div__ object to the new DIV object must somehow break 
down pickle's tracking of the recursive references, resulting in infinite 
recursion during the pickle process.

I'm not sure we actually need the TAG_pickler anyway -- I tried removing 
it, and pickling seemed to work fine, at least in a simple test case. Maybe 
we can get away without it.

For now, though, a workaround would be to render the HTML right in the 
controller so cache.action will cache the raw HTML output instead of 
caching a Python dictionary holding a web2py DOM object. This will also 
speed things up, as web2py will not need to keep re-executing the view on 
each request.  For example:

    return response.render(dict(form=form))

If you don't mind, please open a Github issue about this and link back to 
this post.

Anthony

On Sunday, July 29, 2018 at 2:59:40 PM UTC-4, Joe Barnhart wrote:
>
> I'm using cache.action with cache_model=cache.disk to play with 
> optimization of my site.  To be sure, this page has a lot going on -- 
> complicated menus using "button" objects among the issues.  But I don't 
> have any circular references, at least as far as I can tell.  Still, I get 
> the error:
>
> Traceback (most recent call last):
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/restricted.py", line 219, 
> in restricted
>     exec(ccode, environment)
>   File 
> "/Users/jbarnhart/Work/w2p_env/ss/applications/swim_smarter/controllers/results.py",
>  
> line 29, in <module>
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/globals.py", line 419, in 
> <lambda>
>     self._caller = lambda f: f()
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/cache.py", line 632, in 
> wrapped_f
>     rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire)
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/cache.py", line 467, in 
> __call__
>     self.storage[key] = (now, value)
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/cache.py", line 339, in 
> __setitem__
>     pickle.dump(value, val_file, pickle.HIGHEST_PROTOCOL)
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/html.py", line 1256, in 
> TAG_pickler
>     marshal_dump = pickle.dumps(d, pickle.HIGHEST_PROTOCOL)
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/html.py", line 1256, in 
> TAG_pickler
>     marshal_dump = pickle.dumps(d, pickle.HIGHEST_PROTOCOL)
>   
>   ... some duplication omitted ...
>   
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/html.py", line 1256, in 
> TAG_pickler
>     marshal_dump = pickle.dumps(d, pickle.HIGHEST_PROTOCOL)
>   File "/Users/jbarnhart/Work/w2p_env/ss/gluon/html.py", line 1256, in 
> TAG_pickler
>     marshal_dump = pickle.dumps(d, pickle.HIGHEST_PROTOCOL)
>   File 
> "/Applications/WingIDE.app/Contents/Resources/patches/6.0.12/04-fix-logging-exc/bin/dbg/src/debug/tserver/dbgutils.py",
>  
> line 3409, in wrapper
>   File 
> "/Applications/WingIDE.app/Contents/Resources/patches/6.0.12/04-fix-logging-exc/bin/dbg/src/debug/tserver/dbgutils.py",
>  
> line 2955, in Log
> RuntimeError: maximum recursion depth exceeded
>
> The particular code being pickled, if it matters, looks like this:
>
> <button class="btn btn-primary dropdown-toggle button" 
> data-toggle="dropdown">
>   Male 
> <span class="caret"></span></button>
>
> Followed by:
>
> <button class="btn btn-primary dropdown-toggle button" 
> data-toggle="dropdown">
>   100M Back <span class="caret">
> </span></button>
>
> Over and over.
>
> The full HTML sequence is this.  Note the pair of problem buttons are not 
> adjacent.  But I've never studied the pickler and don't know how it works, 
> so maybe it's not an issue.
>
> <div class="widget-box" id="meettimes">
>  <div class="widget-header">
>   <h3 class="widget-title smaller ">2018 Phoenix Summer Invitation</h3>
>   <div class="widget-toolbar no-border" id="meettimes-tb" style="padding:0 
> 0 0 5px;">
>    <div class="widget-menu">
>     <button class="btn btn-primary dropdown-toggle button" 
> data-toggle="dropdown">
>      Male <span class="caret"</span>
>     </button>
>     <ul class="dropdown-menu dropdown-caret dropdown-close">
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=266&amp;mid=14&amp;stage=F">Female</a></li>
>      <li><a class="" href="#">Male</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=848&amp;mid=14&amp;stage=F">Mixed</a></li>
>     </ul>
>    </div>
>    <div class="widget-menu">
>     <button class="btn btn-primary dropdown-toggle button" 
> data-toggle="dropdown">
>      100M Back <span class="caret"></span>
>     </button>
>     <ul class="dropdown-menu dropdown-caret dropdown-close">
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=106&amp;mid=14&amp;stage=F">50M 
> Free</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=107&amp;mid=14&amp;stage=F">100M 
> Free</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=102&amp;mid=14&amp;stage=F">200M 
> Free</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=299&amp;mid=14&amp;stage=F">400M 
> Free</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=331&amp;mid=14&amp;stage=F">800M 
> Free</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=808&amp;mid=14&amp;stage=F">1500M 
> Free</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=188&amp;mid=14&amp;stage=F">50M 
> Back</a></li>
>      <li><a class="" href="#">100M Back</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=833&amp;mid=14&amp;stage=F">200M 
> Back</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=108&amp;mid=14&amp;stage=F">50M 
> Breast</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=105&amp;mid=14&amp;stage=F">100M 
> Breast</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=832&amp;mid=14&amp;stage=F">200M 
> Breast</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=103&amp;mid=14&amp;stage=F">50M 
> Fly</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=104&amp;mid=14&amp;stage=F">100M 
> Fly</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=866&amp;mid=14&amp;stage=F">200M 
> Fly</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=110&amp;mid=14&amp;stage=F">200M 
> Medley</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=287&amp;mid=14&amp;stage=F">400M 
> Medley</a></li>
>     </ul>
>    </div>
>    <div class="widget-menu">
>     <button class="btn btn-primary dropdown-toggle button" 
> data-toggle="dropdown">
>      11-12 <span class="caret"></span>
>     </button>
>     <ul class="dropdown-menu dropdown-caret dropdown-close">
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=800&amp;mid=14&amp;stage=F">10-Un</a></li>
>      <li><a class="" href="#">11-12</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=151&amp;mid=14&amp;stage=F">13-14</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=823&amp;mid=14&amp;stage=F">15-Ov</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=856&amp;mid=14&amp;stage=F">13-Ov</a></li>
>      <li><a class="disabled" 
> href="/swim_smarter/results/meettimes?eid=848&amp;mid=14&amp;stage=F">Open</a></li>
>     </ul>
>    </div>
>    <div class="widget-menu">
>     <button class="btn btn-primary dropdown-toggle button" 
> data-toggle="dropdown">
>      Finals <span class="caret"></span>
>     </button>
>     <ul class="dropdown-menu dropdown-caret dropdown-close">
>      <li><a class="" href="#">Finals</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=258&amp;mid=14&amp;stage=P">Prelims</a></li>
>      <li><a class="" 
> href="/swim_smarter/results/meettimes?eid=258&amp;mid=14&amp;stage=S">Swim-offs</a></li>
>     </ul>
>    </div>
>   </div>
>  </div>
>  <div class="widget-body">
>   <div class="widget-main no-padding">
>    <table class="table table-striped table-bordered table-hover" 
> data-api="mttabapi" data-var="mttabdv" id="mttab" style="width:100%;">
>    </table>
>   </div>
>  </div>
> </div>
>

-- 
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to