Hi Greg,<br><br><div class="gmail_quote">On Sat, Nov 6, 2010 at 12:24 PM, Greg Hellings <span dir="ltr">&lt;<a href="mailto:greg.hellings@gmail.com">greg.hellings@gmail.com</a>&gt;</span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">


But the nature of multimap is different - and I&#39;m confused as to how<br>
it is used at all.  What you are showing above I would call a<br>
multi-dimensional associative array/dictionary.  I make them all the<br>
time in Python and PHP.  But a multimap is defined as &quot;a<br>
generalization of a map or associative array abstract data type in<br>
which more than one value may be associated with and returned for a<br>
given key.&quot;  I don&#39;t think we are actually using multimap<br>
functionality but rather just a multidimensional array.<br></blockquote><div>If I remember rightly, a multimap is just like a dictionary in python that can have multiple values for a given key (conceptually I guess it is like a dictionary of lists of something).</div>

<div>The getEntryAttributes stuff is not a multimap - just nested maps.</div><div><br></div><div>Multimaps are seen in SWConfig, where it is possible to have multiple entries for a given key (e.g. in modules, multiple GlobalOptionFilter&#39;s).</div>

<div><br></div><div>This allows you to iterate through them like this:</div><div>(annoyingly long fragment adapted from C++, untouched for a year probably...)</div><div><br></div><div># look first in the map</div><div><div>

<span class="Apple-style-span" style="white-space: pre;">sourcesSection = installConf.getSections().find(Sword.SWBuf(&quot;Sources&quot;))
if sourcesSection != installConf.getSections().end():
        ftp_source = Sword.SWBuf(&quot;FTPSource&quot;)
        ss = sourcesSection.value()[1]
        </span></div><div><span class="Apple-style-span" style="white-space: pre;"><meta charset="utf-8">        # this is where we start iterating over the multimap
        sourceBegin = ss.lower_bound(ftp_source)
        sourceEnd = ss.upper_bound(ftp_source)

        while sourceBegin != sourceEnd:
                install_source = InstallSource(&quot;FTP&quot;, 
                        sourceBegin.value()[1].c_str())

                print privatePath + &quot;/&quot; + install_source.source</span></div><div><span class="Apple-style-span" style="white-space: pre;">
                sourceBegin += 1
</span></div></div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
SWIG gives us multimap support in Python for free and I found a<br>
version we include with the library to get Perl working.  However,<br>
SWIG does not have an implementation of stl::multimap for us, so we<br>
either need to write one, or refactor our multimap usage to be nested<br>
associative arrays.<br></blockquote><div> Most people wouldn&#39;t need to touch multimap - I think it&#39;s only used  in SWConfig, where mostly you can just use get and set on the SWConfig if needed (only if you need to iterate over multiple key values). So I don&#39;t think this should worry us too much. To some extent, if an area of the API isn&#39;t supported for a given language, there&#39;s no point in supporting it until someone needs it.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
&gt;<br>
&gt; But this interface doesn&#39;t translate well to other languages.  I have<br>
&gt; had to implement a different interface for my custom language binding<br>
&gt; for Java-jni (used by SWORD C++ on Android) and CORBA (used by SWORDWeb).<br>
&gt;<br>
&gt; The binding interface I usually implement is described in simple IDL<br>
&gt; here and is a fairly concise set of methods that give access to most all<br>
&gt; of functionality of the engine:<br>
&gt;<br>
&gt; <a href="http://crosswire.org/svn/sword/trunk/bindings/corba/swordorb.idl" target="_blank">http://crosswire.org/svn/sword/trunk/bindings/corba/swordorb.idl</a><br>
&gt;<br>
&gt; You&#39;ll notice the method for obtaining entry attributes:<br>
&gt;<br>
&gt; StringList SWModule.getEntryAttribute(in string level1, in string<br>
&gt; level2, in string level3, in boolean filtered);<br>
&gt;<br>
&gt; This less exotic interface maps much easier to other languages, but<br>
&gt; implies you know what attribute you&#39;d like to obtain (discovery by<br>
&gt; iteration is not supported, but really, what frontend does that anyway?)<br></blockquote><div>That might be a better way of doing it, and would be very easy to add. </div><div>In BPBible we don&#39;t exactly iterate over it, but we do get values at different levels and check whether subvalues exist (look at: <a href="http://code.google.com/p/bpbible/source/browse/trunk/backend/book.py#415">http://code.google.com/p/bpbible/source/browse/trunk/backend/book.py#415</a></div>

<div>). This we could replace with a simpler interface in getEntryAttribute (which could return None if key not found).</div><div><br></div><div>I can imagine a situation where someone wanted to do iteration, but we don&#39;t seem to do that in BPBible at the moment...</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
&gt;<br>
&gt; So, in summary, maybe we should add this to swmodule.i<br>
<br>
That is one possibility.  However, I think there are other places<br>
within the bindings that should be addressed first.  As you saw<br>
yourself, SWBuf plays great in C++ but SWIG doesn&#39;t seem to pick up<br>
any ability to auto-cast it back to a Python string/unicode object.<br>
At the very least, that functionality should be as easy as an explicit<br>
cast of unicode(myswbuf) and better yet it would be transparent.<br></blockquote><div>I tried doing that with a simple SWIG typemap, but it didn&#39;t play well with the STL stuff. Almost everything worked as expected, but when a SWBuf was a key in a std::map for example, it didn&#39;t transparently convert that, and there was no way to create SWBuf&#39;s then. </div>

<div>Occasionally it is useful not to transparently convert them but to look at the length or something like that for efficiency (not very common I think...)</div><div> </div><div>Depending on how smart you want to try to make it, SWBuf&#39;s have to end up as byte strings as well quite a bit of the time. There&#39;s no universal way from the API to tell whether something is utf-8 or cp1252. You could do it for a number of key interfaces, though - RenderText, getKeyText, get config entry from module.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Ideally, someone would write extra Python code so that the SWIG<br>
bindings were wrapped in a more naturally Pythonic binding.  It might<br>
be perfectly natural in a language like C++ or Java to access a module<br>
with<br>
<br>
SWMgr* mgr = new SWMgr(FMT_HTMLHREF);<br>
SWModule* mod = mgr-&gt;getModule(&quot;KJV&quot;);<br>
VerseKey* key = (VerseKey*) mod-&gt;getKey();<br>
key-&gt;persist(true);<br>
key = &#39;john 3:1&#39;;<br>
cout &lt;&lt; mod-&gt;RenderText();<br>
<br>
A natural pythonic way of doing this would probably look more like<br>
<br>
mod = Sword.module(&#39;KJV&#39;)<br>
print mod(&#39;john 3:1&#39;, format=&#39;HTMLHREF&#39;)<br></blockquote><div>You could easily put a simple python wrapper around Sword which did this, but this wouldn&#39;t easily cover everything. From my perspective:</div>

<div>1) SWMgr is very necessary to expose for BPBible at least. Probably not in a simple API though.</div><div>2) I don&#39;t like that function style calling, and I wouldn&#39;t say it is pythonic (not that I necessarily am a good judge of that). A method would work better I think - say text or get_text, but taking a string.</div>

<div>3) Passing in format like you did won&#39;t (easily) work as the format is a property of the SWMgr. Unless you keep a SWMgr per format, and look them up and create them when needed. Probably defaulting to HTMLHREF is correct, and then having a module level set format to call which creates a new SWMgr.</div>

<div><br></div><div>Thos problems aside, a simple python wrapper could create a much lower barrier to entry. Personally, I don&#39;t care too much about other languages than Python. </div><div><br></div><div>To some extent, I&#39;ve simplified working with some of the SWORD stuff and done extra checking and whatnot in BPBible, mostly in the file below:</div>

<div><a href="http://code.google.com/p/bpbible/source/browse/trunk/swlib/pysw.py">http://code.google.com/p/bpbible/source/browse/trunk/swlib/pysw.py</a></div><div><br></div><div>This file does quite a bit, mostly with (Verse, Tree, SW, List)Keys. Keys will be the hardest thing to make work nicely, I think. In BPBible we do lots of special stuff with keys, for example formatting ranges nicely, keeping user input segregated from english keys, etc.</div>

<div>The stuff in this file is reasonably tied into BPBible, and so isn&#39;t usable as-is elsewhere.</div><div><br></div><div>An example of how this could look: </div><div>mod = Sword.module(&quot;KJV&quot;)</div><div>print mod.get_text(&quot;John 3:16&quot;)</div>

<div>print mod.get_text(&quot;John 3&quot;)</div><div>for verse, text in mod.chapter(&quot;John 3&quot;):</div><div>    print verse, text</div><div><br></div><div>for reference, text in mod.range(&quot;John 3:1-6&quot;):</div>

<div>    print reference, text</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
But in order to get to that point would take someone writing<br>
native-feeling Pythonic bindings and making design decisions like<br>
that.  I&#39;m tied up with other tasks at the moment and can&#39;t devote the<br>
time to learning SWIG to clean up the warnings and errors the bindings<br>
throw on compile PLUS write native feeling bindings for languages.<br>
But it&#39;d be a great thing for someone to tackle if they really like<br>
their scripting languages and probably wouldn&#39;t require learning much<br>
(if any) C++.<br></blockquote><div>Trying to work with SWIG at all is likely to end up with using C++. If doing any stuff with stl, it is really needed, and even still very hard to get working (I did all the stl map/vector stuff, and it was painful and fragile). A simple wrapper API in python would require understanding SWORD, but possibly not too much C++ unless more SWIG binding needed writing.</div>

<div><br></div><div>As to the warnings from SWIG, some I tried to set SWIG to ignore, but it wouldn&#39;t. So I gave up. Others are possibly valid concerns, but I wasn&#39;t sure how to handle them. Writing SWIG bindings is painful, in case anyone didn&#39;t realise... :-)</div>

<meta charset="utf-8"><div><br></div><div>The bottom line is that SWORD is a complex API, but for a full-featured frontend, a lot of that complexity is necessary.</div><meta charset="utf-8"><br clear="all">God Bless,<br>
Ben<br>
-------------------------------------------------------------------------------------------<br>Multitudes, multitudes,<br>    in the valley of decision!<br>For the day of the LORD is near<br>    in the valley of decision.<br>

<br><div>Giôên 3:14 (ESV) </div></div>